react-stockcharts源码阅读
閱讀時間:全文 1379 字,預估用時 7 分鐘
創作日期:2018-06-28
上篇文章:招React,不容错过
BEGIN
前言
- 项目地址: react-stockcharts 🔗
- demo地址: react-stockcharts-examples2 🔗
代码分析
项目目录
./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,不容错过