UNPKG

@tuofeng/react-native-d3multiline-chart

Version:

Android and iOS multipleline/line/scatter chart based on d3.js, change and use for tuofeng

142 lines (134 loc) 4.33 kB
// @flow /** * Problem: Color props such as fill and stroke cannot be animated through setNativeProps. They can be animated through state, but setNativeProps is better * Solution: Extract brush, update propList (does not seem to do anything but to be consistent extractProps I did it anyway) */ import React, { Component } from 'react'; import Color from 'color'; import pick from 'lodash/pick'; import { listen, removeListeners } from '../AnimatedListener'; import type { AnimatedListener } from '../AnimatedListener'; // https://github.com/react-native-community/react-native-svg/blob/master/lib/extract/extractBrush.js const patternReg = /^url\(#(.+?)\)$/; function extractBrush(colorOrBrush) { if (colorOrBrush === 'none' || !colorOrBrush) { return null; } try { let matched = colorOrBrush.match(patternReg); // brush if (matched) { return [1, matched[1]]; //todo: } else { // solid color let [r, g, b, a = 1] = Color(colorOrBrush).rgb().array(); return [0, r / 255, g / 255, b / 255, a]; } } catch (err) { console.warn(`"${colorOrBrush}" is not a valid color or brush`); return null; } } const fillKeys = ['fill', 'fillOpacity', 'fillRule']; const strokeKeys = [ 'stroke', 'strokeWidth', 'strokeOpacity', 'strokeDasharray', 'strokeDashoffset', 'strokeLinecap', 'strokeLinejoin', 'strokeMiterlimit' ]; function getPropList(nextProps, prevProps) { let propList = []; fillKeys.forEach(name => { if (nextProps.hasOwnProperty(name) || prevProps.hasOwnProperty(name)) { propList.push(name); } }); strokeKeys.forEach(name => { if (nextProps.hasOwnProperty(name) || prevProps.hasOwnProperty(name)) { propList.push(name); } }); return propList; } const separator = /\s*,\s*/; function getStrokeDasharray(strokeDasharray) { if (typeof strokeDasharray === 'string') { strokeDasharray = strokeDasharray.split(separator).map(dash => +dash); } if (strokeDasharray && strokeDasharray.length === 1) { strokeDasharray.push(strokeDasharray[0]); } // have to clone array to allow animation with mutable changes return strokeDasharray ? [...strokeDasharray] : strokeDasharray; } function getStrokeDashoffset(nextProps, prevProps) { const strokeDasharray = getStrokeDasharray(nextProps.strokeDasharray) || getStrokeDasharray(prevProps.strokeDasharray); return strokeDasharray ? +nextProps.strokeDashoffset || +prevProps.strokeDashoffset || 0 : null; } const KEYS = ['fill', 'stroke', 'strokeDashoffset']; export default function SvgBrushFix(WrappedComponent) { return class extends Component { strokeDasharray: AnimatedListener; constructor(props) { super(props); this.updateCache(props); this.strokeDasharray = listen(props.strokeDasharray, _ => this.setNativeProps({ updateStrokeDasharray: true }) ); } updateCache(props) { this.prevProps = pick(props, KEYS); } setNativeProps = props => { props.propList = getPropList(props, this.prevProps); if (props.fill) { props.fill = extractBrush(props.fill); } if (props.stroke) { props.stroke = extractBrush(props.stroke); } if (props.updateStrokeDasharray || props.strokeDashoffset) { props.strokeDasharray = getStrokeDasharray( this.strokeDasharray.values ); props.strokeDashoffset = getStrokeDashoffset( props, this.prevProps ); } this._component && this._component.setNativeProps(props); }; componentWillReceiveProps(nextProps) { this.updateCache(nextProps); if (nextProps.strokeDasharray !== this.props.strokeDasharray) { removeListeners(this.strokeDasharray); this.strokeDasharray = listen(nextProps.strokeDasharray, _ => this.setNativeProps({ updateStrokeDasharray: true }) ); } } componentWillUnmount() { removeListeners(this.strokeDasharray); } render() { const strokeDasharray = getStrokeDasharray( this.strokeDasharray.values ); return ( <WrappedComponent ref={component => (this._component = component)} {...this.props} strokeDasharray={strokeDasharray} /> ); } }; }