目錄:
  1. 前言
    1. 代码分析
      1. 项目目录
        1. 先从最简单的demo开始
          1. dome代码
          2. fitWidth

      react-stockcharts源码阅读

      閱讀時間:全文 1379 字,預估用時 7 分鐘
      創作日期:2018-06-28
      文章標籤:
      上篇文章:招React,不容错过
       
      BEGIN

      前言

      代码分析

      项目目录

      ./react-stockcharts
      ├── index.js
      └── lib
          ├── algorithm
          │   └── index.js
          ├── annotation
          │   ├── Annotate.js
          │   ├── BarAnnotation.js
          │   ├── index.js
          │   ├── LabelAnnotation.js
          │   ├── Label.js
          │   └── SvgPathAnnotation.js
          ├── axes
          │   ├── Axis.js
          │   ├── AxisLine.js
          │   ├── AxisTicks.js
          │   ├── AxisZoomCapture.js
          │   ├── index.js
          │   ├── XAxis.js
          │   └── YAxis.js
          ├── BackgroundText.js
          ├── calculator
          │   ├── atr.js
          │   ├── bollingerband.js
          │   ├── change.js
          │   ├── compare.js
          │   ├── defaultOptionsForComputation.js
          │   ├── elderRay.js
          │   ├── ema.js
          │   ├── forceIndex.js
          │   ├── heikinAshi.js
          │   ├── index.js
          │   ├── kagi.js
          │   ├── macd.js
          │   ├── pointAndFigure.js
          │   ├── renko.js
          │   ├── rsi.js
          │   ├── sar.js
          │   ├── sma.js
          │   ├── smoothedForceIndex.js
          │   ├── sto.js
          │   ├── tma.js
          │   └── wma.js
          ├── CanvasContainer.js
          ├── ChartCanvas.js
          ├── Chart.js
          ├── coordinates
          │   ├── CrossHairCursor.js
          │   ├── CurrentCoordinate.js
          │   ├── Cursor.js
          │   ├── EdgeCoordinate.js
          │   ├── EdgeCoordinateV2.js
          │   ├── EdgeCoordinateV3.js
          │   ├── EdgeIndicator.js
          │   ├── index.js
          │   ├── MouseCoordinateX.js
          │   ├── MouseCoordinateXV2.js
          │   ├── MouseCoordinateY.js
          │   └── PriceCoordinate.js
          ├── EventCapture.js
          ├── GenericChartComponent.js
          ├── GenericComponent.js
          ├── helper
          │   ├── fitDimensions.js
          │   ├── fitWidth.js
          │   ├── index.js
          │   ├── SaveChartAsImage.js
          │   └── TypeChooser.js
          ├── indicator
          │   ├── atr.js
          │   ├── baseIndicator.js
          │   ├── bollingerBand.js
          │   ├── change.js
          │   ├── compare.js
          │   ├── defaultOptionsForAppearance.js
          │   ├── elderImpulse.js
          │   ├── elderRay.js
          │   ├── ema.js
          │   ├── forceIndex.js
          │   ├── heikinAshi.js
          │   ├── index.js
          │   ├── kagi.js
          │   ├── macd.js
          │   ├── pointAndFigure.js
          │   ├── renko.js
          │   ├── rsi.js
          │   ├── sar.js
          │   ├── sma.js
          │   ├── stochasticOscillator.js
          │   ├── tma.js
          │   └── wma.js
          ├── interactive
          │   ├── Brush.js
          │   ├── ClickCallback.js
          │   ├── components
          │   │   ├── ChannelWithArea.js
          │   │   ├── ClickableCircle.js
          │   │   ├── ClickableShape.js
          │   │   ├── GannFan.js
          │   │   ├── HoverTextNearMouse.js
          │   │   ├── InteractiveText.js
          │   │   ├── InteractiveYCoordinate.js
          │   │   ├── LinearRegressionChannelWithArea.js
          │   │   ├── MouseLocationIndicator.js
          │   │   ├── StraightLine.js
          │   │   └── Text.js
          │   ├── DrawingObjectSelector.js
          │   ├── EquidistantChannel.js
          │   ├── FibonacciRetracement.js
          │   ├── GannFan.js
          │   ├── index.js
          │   ├── InteractiveText.js
          │   ├── InteractiveYCoordinate.js
          │   ├── StandardDeviationChannel.js
          │   ├── TrendLine.js
          │   ├── utils.js
          │   └── wrapper
          │       ├── EachEquidistantChannel.js
          │       ├── EachFibRetracement.js
          │       ├── EachGannFan.js
          │       ├── EachInteractiveYCoordinate.js
          │       ├── EachLinearRegressionChannel.js
          │       ├── EachText.js
          │       └── EachTrendLine.js
          ├── scale
          │   ├── discontinuousTimeScaleProvider.js
          │   ├── evaluator.js
          │   ├── financeDiscontinuousScale.js
          │   ├── index.js
          │   └── levels.js
          ├── series
          │   ├── AlternatingFillAreaSeries.js
          │   ├── AreaOnlySeries.js
          │   ├── AreaSeries.js
          │   ├── BarSeries.js
          │   ├── BollingerSeries.js
          │   ├── CandlestickSeries.js
          │   ├── CircleMarker.js
          │   ├── ElderRaySeries.js
          │   ├── GroupedBarSeries.js
          │   ├── index.js
          │   ├── KagiSeries.js
          │   ├── LineSeries.js
          │   ├── MACDSeries.js
          │   ├── OHLCSeries.js
          │   ├── OverlayBarSeries.js
          │   ├── PointAndFigureSeries.js
          │   ├── RenkoSeries.js
          │   ├── RSISeries.js
          │   ├── SARSeries.js
          │   ├── ScatterSeries.js
          │   ├── SquareMarker.js
          │   ├── StackedBarSeries.js
          │   ├── StochasticSeries.js
          │   ├── StraightLine.js
          │   ├── SVGComponent.js
          │   ├── TriangleMarker.js
          │   └── VolumeProfileSeries.js
          ├── tooltip
          │   ├── BollingerBandTooltip.js
          │   ├── displayValuesFor.js
          │   ├── GroupTooltip.js
          │   ├── HoverTooltip.js
          │   ├── index.js
          │   ├── MACDTooltip.js
          │   ├── MovingAverageTooltip.js
          │   ├── OHLCTooltip.js
          │   ├── RSITooltip.js
          │   ├── SingleValueTooltip.js
          │   ├── StochasticTooltip.js
          │   ├── ToolTipText.js
          │   └── ToolTipTSpanLabel.js
          ├── utils
          │   ├── accumulatingWindow.js
          │   ├── barWidth.js
          │   ├── ChartDataUtil.js
          │   ├── identity.js
          │   ├── index.js
          │   ├── mappedSlidingWindow.js
          │   ├── merge.js
          │   ├── noop.js
          │   ├── PureComponent.js
          │   ├── rebind.js
          │   ├── shallowEqual.js
          │   ├── slidingWindow.js
          │   ├── strokeDasharray.js
          │   ├── zipper.js
          │   └── zoomBehavior.js
          └── ZoomButtons.js
      ./react-stockcharts-examples2/examples
      ├── AreaChart
      ├── AreaChartWithYPercent
      ├── AreaChartWithZoomPan
      ├── BarChart
      ├── BubbleChart
      ├── CandleStickChart
      ├── CandleStickChartForContinuousIntraDay
      ├── CandleStickChartForDiscontinuousIntraDay
      ├── CandleStickChartPanToLoadMore
      ├── CandleStickChartWithAnnotation
      ├── CandleStickChartWithBollingerBandOverlay
      ├── CandleStickChartWithBrush
      ├── CandleStickChartWithCHMousePointer
      ├── CandleStickChartWithClickHandlerCallback
      ├── CandleStickChartWithCompare
      ├── CandleStickChartWithDarkTheme
      ├── CandleStickChartWithEdge
      ├── CandleStickChartWithEquidistantChannel
      ├── CandleStickChartWithFibonacciInteractiveIndicator
      ├── CandleStickChartWithForceIndexIndicator
      ├── CandleStickChartWithFullStochasticsIndicator
      ├── CandleStickChartWithGannFan
      ├── CandleStickChartWithHoverTooltip
      ├── CandleStickChartWithInteractiveIndicator
      ├── CandleStickChartWithInteractiveYCoordinate
      ├── CandleStickChartWithMA
      ├── CandleStickChartWithMACDIndicator
      ├── CandleStickChartWithPriceMarkers
      ├── CandleStickChartWithRSIIndicator
      ├── CandleStickChartWithSAR
      ├── CandleStickChartWithStandardDeviationChannel
      ├── CandleStickChartWithText
      ├── CandleStickChartWithUpdatingData
      ├── CandleStickChartWithZoomPan
      ├── CandleStickStockScaleChart
      ├── CandleStickStockScaleChartWithVolumeBarV1
      ├── CandleStickStockScaleChartWithVolumeBarV2
      ├── CandleStickStockScaleChartWithVolumeBarV3
      ├── GroupedBarChart
      ├── HeikinAshi
      ├── HorizontalBarChart
      ├── HorizontalStackedBarChart
      ├── Kagi
      ├── KagiWithUpdatingData
      ├── LineAndScatterChart
      ├── LineAndScatterChartGrid
      ├── MovingAverageCrossOverAlgorithmV1
      ├── MovingAverageCrossOverAlgorithmV2
      ├── OHLCChartWithElderImpulseIndicator
      ├── OHLCChartWithElderRayIndicator
      ├── PointAndFigure
      ├── PointAndFigureWithUpdatingData
      ├── Renko
      ├── RenkoWithUpdatingData
      ├── StackedBarChart
      ├── VolumeProfileBySessionChart
      └── VolumeProfileChart

      先从最简单的demo开始

      遵循从内往外深度挖掘原则

      dome代码

      • demo名: BarChart
      import { scalePoint } from  "d3-scale";
      import React from "react";
      import { render } from 'react-dom';
      import PropTypes from "prop-types";
      
      import { ChartCanvas, Chart } from "react-stockcharts";
      import { BarSeries } from "react-stockcharts/lib/series";
      import { XAxis, YAxis } from "react-stockcharts/lib/axes";
      import { fitWidth } from "react-stockcharts/lib/helper";
      
      class BarChart extends React.Component {
        render() {
          const { data: unsortedData, type, width, ratio } = this.props;
          const data = unsortedData.slice().sort((a, b) => a.income - b.income);
      
          return (
            <ChartCanvas ratio={ratio}
              width={width}
              height={400}
              margin={{ left: 80, right: 10, top: 20, bottom: 30 }}
              type={type}
              seriesName="Fruits"
              xExtents={list => list.map(d => d.x)}
              data={data}
              xAccessor={d => d.x}
              xScale={scalePoint()}
              padding={1}
            >
              <Chart id={1} yExtents={d => [0, d.y]}>
                <XAxis axisAt="bottom" orient="bottom" />
                <YAxis axisAt="left" orient="left" />
                <BarSeries yAccessor={d => d.y} />
              </Chart>
            </ChartCanvas>
      
          );
        }
      }
      
      BarChart.propTypes = {
        data: PropTypes.array.isRequired,
        width: PropTypes.number.isRequired,
        ratio: PropTypes.number.isRequired,
        type: PropTypes.oneOf(["svg", "hybrid"]).isRequired,
      };
      
      BarChart.defaultProps = {
        type: "svg",
      };
      
      BarChart = fitWidth(BarChart);
      
      let data = []; // 图表显示数据
      
      render(
        <Chart type='hybrid' data={data} />
        document.getElementById("root")
      );

      fitWidth

      • 文件路径: react-stockcharts/es/lib/helper/fitWidth.js
      • 函数功能: 修饰器函数, 计算出容器宽和比值传入被修饰组件, 用react讲其实就是一个高阶组件

      代码结构

      import React, { Component } from "react";
      var _extends = Object.assign || function (target) {
        /* ************
         * 用于多个对象的合并, 其中工具库lodash也提供了extend方式实现相同功能
         * params: target, obj1, obj2, ...
         * paramsType: Object
         * return: target
         * ************/
        for (var i = 1; i < arguments.length; i++) {
          var source = arguments[i];
          for (var key in source) {
            if (Object.prototype.hasOwnProperty.call(source, key)) {
              target[key] = source[key];
            }
          }
        }
        return target;
      };
      
      var _createClass = function () {
        /* ************
         * 立即执行闭包函数, 返回新函数
         * 将参数数组中的属性赋值给类对象, 理解上与_extends方法相似, 前者是对象合并到对象, 后者是对象合并到类
         * params: Constructor, protoProps, staticProps
         * paramsType:
         *   Constructor: 目标对象, Function
         *   protoProps: 属性数组, Array[{key: value}, ...], Constructor.prototype[key] = value
         *   staticProps: 属性数组, Array[{key: value}, ...], Constructor[key] = value
         * return: Constructor
         * ************/
        function defineProperties(target, props) {
          for (var i = 0; i < props.length; i++) {
            var descriptor = props[i];
            descriptor.enumerable = descriptor.enumerable || false;
            descriptor.configurable = true;
            if ("value" in descriptor) descriptor.writable = true;
            Object.defineProperty(target, descriptor.key, descriptor);
          }
        }
        return function (Constructor, protoProps, staticProps) {
          if (protoProps) defineProperties(Constructor.prototype, protoProps);
          if (staticProps) defineProperties(Constructor, staticProps);
          return Constructor;
        };
      }();
      
      function _inherits(subClass, superClass) {
        /* ************
         * 实现类继承
         * params: subClass, superClass
         * paramsType:
         *   subClass: 子类, Function
         *   superClass: 父类, Function
         * return: null
         * ************/
        if (typeof superClass !== "function" && superClass !== null) {
          throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
        }
        subClass.prototype = Object.create(superClass && superClass.prototype, {
          constructor: {
            // ES3中规定对象属性有writable等私有属性, 若不设置writable为true则obj.constructor值将不能修改
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
          }
        });
        if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
      }
      
      export default function fitWidth(WrappedComponent, withRef = true, minWidth = 100) {
        class ResponsiveComponent extends Component {
          constructor(props) {
            super(props);
            this.handleWindowResize = this.handleWindowResize.bind(this);
            this.getWrappedInstance = this.getWrappedInstance.bind(this);
            this.saveNode = this.saveNode.bind(this);
            this.setTestCanvas = this.setTestCanvas.bind(this);
            this.state = {};
          }
      
          ...
      
          render() {
            const ref = withRef ? { ref: this.saveNode } : {};
      
            if (this.state.width) {
              return <WrappedComponent width={this.state.width} ratio={this.state.ratio} {...this.props} {...ref} />;
            } else {
              return <div {...ref}>
                <canvas ref={this.setTestCanvas}  />
              </div>;
            }
          }
        }
      
        ResponsiveComponent.displayName = `fitWidth(${ getDisplayName(WrappedComponent) })`;
      
        return ResponsiveComponent;
      }
      FINISH
      上篇文章:招React,不容错过

      隨機文章
      人生倒計時
      default