index.js 3.04 KB
Newer Older
niko's avatar
niko committed
1 2
import React, { Component } from 'react';
import { Chart, Axis, Tooltip, Geom } from 'bizcharts';
3
import Debounce from 'lodash-decorators/debounce';
afc163's avatar
afc163 committed
4
import Bind from 'lodash-decorators/bind';
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
5
import ResizeObserver from 'resize-observer-polyfill';
6 7
import styles from '../index.less';

niko's avatar
niko committed
8
class Bar extends Component {
9
  state = {
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
10 11
    width: 0,
    height: 0,
12
    autoHideXLabels: false,
niko's avatar
niko committed
13
  };
14

15
  componentDidMount() {
jim's avatar
jim committed
16
    window.addEventListener('resize', this.resize, { passive: true });
17 18
  }

19
  componentWillUnmount() {
20
    window.removeEventListener('resize', this.resize);
21 22
  }

23 24 25 26 27 28 29 30
  handleRoot = n => {
    this.root = n;
  };

  handleRef = n => {
    this.node = n;
  };

ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
  resizeObserver() {
    const ro = new ResizeObserver(entries => {
      const { width, height } = entries[0].contentRect;
      this.setState((preState, { hasLegend }) => {
        if (preState.width !== width || preState.height !== height) {
          return {
            width: width - (hasLegend ? 240 : 0),
            height,
          };
        }
        return null;
      });
    });
    if (this.root) {
      ro.observe(this.root);
    }
  }

afc163's avatar
afc163 committed
49
  @Bind()
niko's avatar
niko committed
50
  @Debounce(400)
afc163's avatar
afc163 committed
51
  resize() {
52 53 54
    if (!this.node) {
      return;
    }
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
55 56 57 58 59 60 61
    const canvasWidth = this.node.parentNode.clientWidth;
    const { data = [], autoLabel = true } = this.props;
    if (!autoLabel) {
      return;
    }
    const minWidth = data.length * 30;
    const { autoHideXLabels } = this.state;
62

ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
63 64
    if (canvasWidth <= minWidth) {
      if (!autoHideXLabels) {
65
        this.setState({
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
66
          autoHideXLabels: true,
67 68
        });
      }
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
69 70 71 72 73
    } else if (autoHideXLabels) {
      this.setState({
        autoHideXLabels: false,
      });
    }
74 75
  }

niko's avatar
niko committed
76
  render() {
nikogu's avatar
nikogu committed
77
    const {
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
78
      height: propsHeight,
nikogu's avatar
nikogu committed
79 80 81 82 83 84
      title,
      forceFit = true,
      data,
      color = 'rgba(24, 144, 255, 0.85)',
      padding,
    } = this.props;
85

niko's avatar
niko committed
86
    const { autoHideXLabels } = this.state;
87

niko's avatar
niko committed
88
    const scale = {
89 90 91 92 93 94
      x: {
        type: 'cat',
      },
      y: {
        min: 0,
      },
niko's avatar
niko committed
95
    };
96

niko's avatar
niko committed
97 98 99 100 101 102 103
    const tooltip = [
      'x*y',
      (x, y) => ({
        name: x,
        value: y,
      }),
    ];
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
104 105
    const { height: stateHeight, width } = this.state;
    const height = propsHeight || stateHeight;
106
    return (
niko's avatar
niko committed
107 108
      <div className={styles.chart} style={{ height }} ref={this.handleRoot}>
        <div ref={this.handleRef}>
nikogu's avatar
nikogu committed
109
          {title && <h4 style={{ marginBottom: 20 }}>{title}</h4>}
niko's avatar
niko committed
110 111
          <Chart
            scale={scale}
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
112
            width={width}
nikogu's avatar
nikogu committed
113
            height={title ? height - 41 : height}
niko's avatar
niko committed
114 115 116 117
            forceFit={forceFit}
            data={data}
            padding={padding || 'auto'}
          >
nikogu's avatar
nikogu committed
118 119 120 121 122 123 124
            <Axis
              name="x"
              title={false}
              label={autoHideXLabels ? false : {}}
              tickLine={autoHideXLabels ? false : {}}
            />
            <Axis name="y" min={0} />
niko's avatar
niko committed
125 126 127
            <Tooltip showTitle={false} crosshairs={false} />
            <Geom type="interval" position="x*y" color={color} tooltip={tooltip} />
          </Chart>
128 129 130 131 132 133 134
        </div>
      </div>
    );
  }
}

export default Bar;