index.js 2.86 KB
Newer Older
niko's avatar
niko committed
1 2 3 4 5
import React from 'react';
import { Chart, Tooltip, Geom, Legend, Axis } from 'bizcharts';
import DataSet from '@antv/data-set';
import Slider from 'bizcharts-plugin-slider';
import autoHeight from '../autoHeight';
6 7
import styles from './index.less';

niko's avatar
niko committed
8 9 10 11 12 13 14 15 16 17
@autoHeight()
export default class TimelineChart extends React.Component {
  render() {
    const {
      title,
      height = 400,
      padding = [60, 20, 40, 40],
      titleMap = {
        y1: 'y1',
        y2: 'y2',
18
      },
niko's avatar
niko committed
19 20 21 22 23 24 25 26 27 28 29
      borderWidth = 2,
      data = [
        {
          x: 0,
          y1: 0,
          y2: 0,
        },
      ],
    } = this.props;

    data.sort((a, b) => a.x - b.x);
30

31 32
    let max;
    if (data[0] && data[0].y1 && data[0].y2) {
niko's avatar
niko committed
33 34 35 36
      max = Math.max(
        [...data].sort((a, b) => b.y1 - a.y1)[0].y1,
        [...data].sort((a, b) => b.y2 - a.y2)[0].y2
      );
37 38
    }

niko's avatar
niko committed
39 40 41 42
    const ds = new DataSet({
      state: {
        start: data[0].x,
        end: data[data.length - 1].x,
43
      },
niko's avatar
niko committed
44 45 46 47 48 49 50
    });

    const dv = ds.createView();
    dv
      .source(data)
      .transform({
        type: 'filter',
jim's avatar
jim committed
51
        callback: obj => {
niko's avatar
niko committed
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
          const date = obj.x;
          return date <= ds.state.end && date >= ds.state.start;
        },
      })
      .transform({
        type: 'map',
        callback(row) {
          const newRow = { ...row };
          newRow[titleMap.y1] = row.y1;
          newRow[titleMap.y2] = row.y2;
          return newRow;
        },
      })
      .transform({
        type: 'fold',
        fields: [titleMap.y1, titleMap.y2], // 展开字段集
        key: 'key', // key字段
        value: 'value', // value字段
      });

    const timeScale = {
      type: 'time',
74 75
      tickInterval: 60 * 60 * 1000,
      mask: 'HH:mm',
niko's avatar
niko committed
76 77 78 79 80 81
      range: [0, 1],
    };

    const cols = {
      x: timeScale,
      value: {
82
        max,
83 84
        min: 0,
      },
niko's avatar
niko committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    };

    const SliderGen = () => (
      <Slider
        padding={[0, padding[1] + 20, 0, padding[3]]}
        width="auto"
        height={26}
        xAxis="x"
        yAxis="y1"
        scales={{ x: timeScale }}
        data={data}
        start={ds.state.start}
        end={ds.state.end}
        backgroundChart={{ type: 'line' }}
        onChange={({ startValue, endValue }) => {
          ds.setState('start', startValue);
          ds.setState('end', endValue);
        }}
      />
    );
105 106

    return (
niko's avatar
niko committed
107
      <div className={styles.timelineChart} style={{ height: height + 30 }}>
108
        <div>
niko's avatar
niko committed
109 110 111 112 113 114 115 116 117 118
          {title && <h4>{title}</h4>}
          <Chart height={height} padding={padding} data={dv} scale={cols} forceFit>
            <Axis name="x" />
            <Tooltip />
            <Legend name="key" position="top" />
            <Geom type="line" position="x*value" size={borderWidth} color="key" />
          </Chart>
          <div style={{ marginRight: -20 }}>
            <SliderGen />
          </div>
119 120 121 122 123
        </div>
      </div>
    );
  }
}