如何在 React Native 项目中制作水平时间线?

问题描述

我有一个对象数组。每个对象都有时间和状态。另外,我有一个具有特定值的时间范围,我需要在时间轴上显示它:

I want the result something like that

我想需要使用“react-native-svg”和“react-native-svg-charts”,但我不明白如何制作时间线。

如果可以,请提出解决方案。

解决方法

我已经解决了这个问题:

import React from "react";
import PropTypes from "prop-types";
import {StyleSheet,View} from "react-native";
import Icons from "react-native-vector-icons/MaterialIcons";
import {LineChart,Path} from "react-native-svg-charts";
import {ClipPath,Defs,ForeignObject,G,Rect} from "react-native-svg";
import {connect} from "react-redux";
import * as shape from "d3-shape";
import colors from "../../../styles/colors";

const TimeLine = (props) => {
    
    
    // props.info.distractions - the array of red lines on the timeline (green line)

    const startTime = props.info.startTs; //  the start value of the timeline (GREEN line)
    const endTime = props.info.endTs; // the end time value of the timeline (GREEN line)

    const data = [0,0];
    const line = shape.curveBasis;

    // Get coefficients to scale the array of red lines  into the timeline (green line)
    const getCoefficients = (distraction) => {
        const wholeTime = endTime - startTime;
        const dZone = distraction;
        const a1 = dZone.start - startTime;
        const a2 = dZone.end - endTime;
        const startCoefficient = a1 / wholeTime;
        const endCoefficient = a2 / wholeTime;
        return {startCoefficient,endCoefficient};
    };

    // To render a red line on the timeline (green line)
    const RenderLine = ({width,distraction,index}) => {
        const {startCoefficient,endCoefficient} = getCoefficients(distraction);

        return (
            <ClipPath id={`clip-path-${index + 1}`}>
                <Rect
                    x={startCoefficient * width}
                    y={"0"}
                    width={endCoefficient * width}
                    height={"100%"}
                />
            </ClipPath>
        );
    };

    // To render a red line on the timeline (green line)
    const DistractionLine = ({line,index}) => {
        return (
            <G key={index}>
                <Path
                    key={`line-${index + 1}`}
                    d={line}
                    stroke={colors.red}
                    strokeWidth={6}
                    fill={"none"}
                    clipPath={`url(#clip-path-${index + 1})`}
                />
            </G>
        );
    };

    // To render an icon
    const ChartPoint = ({width,endCoefficient} = getCoefficients(distraction);

        return (
            <ForeignObject
                x={(startCoefficient * width + endCoefficient * width) / 2}
                y={40}
                width={100}
                height={40}>
                <Icons name={"touch-app"} color={colors.red} size={24} />
            </ForeignObject>
        );
    };


    // To render the timeline (green line)
    const Clips = ({x,y,width}) => {
        return (
            <Defs key={"clips"}>
                <ClipPath id="clip-path-0">
                    <Rect x={"0"} y={"0"} width={width} height={"100%"} />
                </ClipPath>
                {props.info.distractions.map((distraction,index) => (
                    <RenderLine
                        key={index}
                        index={index}
                        distraction={distraction}
                        width={width}
                    />
                ))}
            </Defs>
        );
    };



    return (
        <View style={styles.chartContainer}>
            <Icons
                name={"radio-button-checked"}
                size={24}
                color={colors.red}
                style={{marginRight: -2,marginBottom: 10}}
            />
            <LineChart
                style={{height: 70,width: "90%"}}
                data={data}
                contentInset={{top: 0,bottom: 40}}
                curve={line}
                svg={{
                    stroke: colors.green,strokeWidth: 6,clipPath: "url(#clip-path-0)",}}>
                <Clips />

                {props.info.distractions.map((distraction,index) => (
                    <ChartPoint
                        key={index}
                        index={index}
                        distraction={distraction}
                    />
                ))}
                {props.info.distractions.map((distraction,index) => (
                    <DistractionLine
                        key={index}
                        index={index}
                        distraction={distraction}
                    />
                ))}
            </LineChart>
            <Icons
                name={"place"}
                size={24}
                color={colors.red}
                style={{marginLeft: -6,marginBottom: 10}}
            />
        </View>
    );
};

TimeLine.defaultProps = {
  info: {},};

TimeLine.propTypes = {
  info: PropTypes.object,};

const styles = StyleSheet.create({
  chartContainer: {
    marginTop: 20,flexDirection: "row",padding: 20,paddingVertical: 20,backgroundColor: "#fff",justifyContent: "center",alignItems: "center",},});

const mapStateToProps = (state) => {
  const { infoReducer } = state;
  return {
    info: infoReducer.info,};
};

export default connect(mapStateToProps)(TimeLine);