UNPKG

ct-react-stockcharts

Version:

Highly customizable stock charts with ReactJS and d3

386 lines (309 loc) 13.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _extends = Object.assign || function (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 () { 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; }; }(); var _react = require("react"); var _react2 = _interopRequireDefault(_react); var _propTypes = require("prop-types"); var _propTypes2 = _interopRequireDefault(_propTypes); var _d3Array = require("d3-array"); var _d3Collection = require("d3-collection"); var _d3Scale = require("d3-scale"); var _GenericChartComponent = require("../GenericChartComponent"); var _GenericChartComponent2 = _interopRequireDefault(_GenericChartComponent); var _GenericComponent = require("../GenericComponent"); var _utils = require("../utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { 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: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var VolumeProfileSeries = function (_Component) { _inherits(VolumeProfileSeries, _Component); function VolumeProfileSeries(props) { _classCallCheck(this, VolumeProfileSeries); var _this = _possibleConstructorReturn(this, (VolumeProfileSeries.__proto__ || Object.getPrototypeOf(VolumeProfileSeries)).call(this, props)); _this.renderSVG = _this.renderSVG.bind(_this); _this.drawOnCanvas = _this.drawOnCanvas.bind(_this); return _this; } _createClass(VolumeProfileSeries, [{ key: "drawOnCanvas", value: function drawOnCanvas(ctx, moreProps) { var xAccessor = moreProps.xAccessor, width = moreProps.width; var _helper = helper(this.props, moreProps, xAccessor, width), rects = _helper.rects, sessionBg = _helper.sessionBg; _drawOnCanvas(ctx, this.props, rects, sessionBg); } }, { key: "render", value: function render() { return _react2.default.createElement(_GenericChartComponent2.default, { svgDraw: this.renderSVG, canvasDraw: this.drawOnCanvas, canvasToDraw: _GenericComponent.getAxisCanvas, drawOn: ["pan"] }); } }, { key: "renderSVG", value: function renderSVG(moreProps) { var _props = this.props, className = _props.className, opacity = _props.opacity; var _props2 = this.props, showSessionBackground = _props2.showSessionBackground, sessionBackGround = _props2.sessionBackGround, sessionBackGroundOpacity = _props2.sessionBackGroundOpacity; var xAccessor = moreProps.xAccessor, width = moreProps.width; var _helper2 = helper(this.props, moreProps, xAccessor, width), rects = _helper2.rects, sessionBg = _helper2.sessionBg; var sessionBgSvg = showSessionBackground ? sessionBg.map(function (d, idx) { return _react2.default.createElement("rect", _extends({ key: idx }, d, { opacity: sessionBackGroundOpacity, fill: sessionBackGround })); }) : null; return _react2.default.createElement( "g", { className: className }, sessionBgSvg, rects.map(function (d, i) { return _react2.default.createElement( "g", { key: i }, _react2.default.createElement("rect", { x: d.x, y: d.y, width: d.w1, height: d.height, fill: d.fill1, stroke: d.stroke1, fillOpacity: opacity }), _react2.default.createElement("rect", { x: d.x + d.w1, y: d.y, width: d.w2, height: d.height, fill: d.fill2, stroke: d.stroke2, fillOpacity: opacity }) ); }) ); } }]); return VolumeProfileSeries; }(_react.Component); VolumeProfileSeries.propTypes = { className: _propTypes2.default.string, opacity: _propTypes2.default.number, showSessionBackground: _propTypes2.default.bool, sessionBackGround: _propTypes2.default.string, sessionBackGroundOpacity: _propTypes2.default.number }; VolumeProfileSeries.defaultProps = { className: "line ", bins: 20, opacity: 0.5, maxProfileWidthPercent: 50, fill: function fill(_ref) { var type = _ref.type; return type === "up" ? "#6BA583" : "#FF0000"; }, stroke: "#FFFFFF", showSessionBackground: false, sessionBackGround: "#4682B4", sessionBackGroundOpacity: 0.3, source: function source(d) { return d.close; }, volume: function volume(d) { return d.volume; }, absoluteChange: function absoluteChange(d) { return d.absoluteChange; }, bySession: false, /* eslint-disable no-unused-vars */ sessionStart: function sessionStart(_ref2) { var d = _ref2.d, i = _ref2.i, plotData = _ref2.plotData; return i > 0 && plotData[i - 1].date.getMonth() !== d.date.getMonth(); }, /* eslint-enable no-unused-vars */ orient: "left", // // fill: ({ type }) => { var c = type === "up" ? "#6BA583" : "#FF0000"; console.log(type, c); return c }, // stroke: ({ type }) => type === "up" ? "#6BA583" : "#FF0000", // stroke: "none", partialStartOK: true, partialEndOK: true }; function helper(props, moreProps, xAccessor, width) { var realXScale = moreProps.xScale, yScale = moreProps.chartConfig.yScale, plotData = moreProps.plotData; var sessionStart = props.sessionStart, bySession = props.bySession, partialStartOK = props.partialStartOK, partialEndOK = props.partialEndOK; var bins = props.bins, maxProfileWidthPercent = props.maxProfileWidthPercent, source = props.source, volume = props.volume, absoluteChange = props.absoluteChange, orient = props.orient, fill = props.fill, stroke = props.stroke; var sessionBuilder = (0, _utils.accumulatingWindow)().discardTillStart(!partialStartOK).discardTillEnd(!partialEndOK).accumulateTill(function (d, i) { return sessionStart(_extends({ d: d, i: i }, moreProps)); }).accumulator(_utils.identity); var dx = plotData.length > 1 ? realXScale(xAccessor(plotData[1])) - realXScale(xAccessor((0, _utils.head)(plotData))) : 0; var sessions = bySession ? sessionBuilder(plotData) : [plotData]; var allRects = sessions.map(function (session) { var begin = bySession ? realXScale(xAccessor((0, _utils.head)(session))) : 0; var finish = bySession ? realXScale(xAccessor((0, _utils.last)(session))) : width; var sessionWidth = finish - begin + dx; // console.log(session) /* var histogram = d3.layout.histogram() .value(source) .bins(bins);*/ var histogram2 = (0, _d3Array.histogram)() // .domain(xScale.domain()) .value(source).thresholds(bins); // console.log(bins, histogram(session)) // console.log(bins, histogram2(session)) var rollup = (0, _d3Collection.nest)().key(function (d) { return d.direction; }).sortKeys(orient === "right" ? _d3Array.descending : _d3Array.ascending).rollup(function (leaves) { return (0, _d3Array.sum)(leaves, function (d) { return d.volume; }); }); var values = histogram2(session); // console.log("values", values) var volumeInBins = values.map(function (arr) { return arr.map(function (d) { return absoluteChange(d) > 0 ? { direction: "up", volume: volume(d) } : { direction: "down", volume: volume(d) }; }); }).map(function (arr) { return rollup.entries(arr); }); // console.log("volumeInBins", volumeInBins) var volumeValues = volumeInBins.map(function (each) { return (0, _d3Array.sum)(each.map(function (d) { return d.value; })); }); // console.log("volumeValues", volumeValues) var base = function base(xScale) { return (0, _utils.head)(xScale.range()); }; var _ref3 = orient === "right" ? [begin, begin + sessionWidth * maxProfileWidthPercent / 100] : [finish, finish - sessionWidth * (100 - maxProfileWidthPercent) / 100], _ref4 = _slicedToArray(_ref3, 2), start = _ref4[0], end = _ref4[1]; var xScale = (0, _d3Scale.scaleLinear)().domain([0, (0, _d3Array.max)(volumeValues)]).range([start, end]); // console.log(xScale.domain()) var totalVolumes = volumeInBins.map(function (volumes) { var totalVolume = (0, _d3Array.sum)(volumes, function (d) { return d.value; }); var totalVolumeX = xScale(totalVolume); var width = base(xScale) - totalVolumeX; var x = width < 0 ? totalVolumeX + width : totalVolumeX; var ws = volumes.map(function (d) { return { type: d.key, width: d.value * Math.abs(width) / totalVolume }; }); return { x: x, ws: ws, totalVolumeX: totalVolumeX }; }); // console.log("totalVolumes", totalVolumes) var rects = (0, _d3Array.zip)(values, totalVolumes).map(function (_ref5) { var _ref6 = _slicedToArray(_ref5, 2), d = _ref6[0], _ref6$ = _ref6[1], x = _ref6$.x, ws = _ref6$.ws; var w1 = ws[0] || { type: "up", width: 0 }; var w2 = ws[1] || { type: "down", width: 0 }; return { // y: yScale(d.x + d.dx), y: yScale(d.x1), // height: yScale(d.x - d.dx) - yScale(d.x), height: yScale(d.x1) - yScale(d.x0), x: x, width: width, w1: w1.width, w2: w2.width, stroke1: (0, _utils.functor)(stroke)(w1), stroke2: (0, _utils.functor)(stroke)(w2), fill1: (0, _utils.functor)(fill)(w1), fill2: (0, _utils.functor)(fill)(w2) }; }); // console.log("rects", rects) var sessionBg = { x: begin, y: (0, _utils.last)(rects).y, height: (0, _utils.head)(rects).y - (0, _utils.last)(rects).y + (0, _utils.head)(rects).height, width: sessionWidth }; return { rects: rects, sessionBg: sessionBg }; }); return { rects: (0, _d3Array.merge)(allRects.map(function (d) { return d.rects; })), sessionBg: allRects.map(function (d) { return d.sessionBg; }) }; } function _drawOnCanvas(ctx, props, rects, sessionBg) { var opacity = props.opacity, sessionBackGround = props.sessionBackGround, sessionBackGroundOpacity = props.sessionBackGroundOpacity, showSessionBackground = props.showSessionBackground; // var { rects, sessionBg } = helper(props, xScale, yScale, plotData); if (showSessionBackground) { ctx.fillStyle = (0, _utils.hexToRGBA)(sessionBackGround, sessionBackGroundOpacity); sessionBg.forEach(function (each) { var x = each.x, y = each.y, height = each.height, width = each.width; ctx.beginPath(); ctx.rect(x, y, width, height); ctx.closePath(); ctx.fill(); }); } rects.forEach(function (each) { var x = each.x, y = each.y, height = each.height, w1 = each.w1, w2 = each.w2, stroke1 = each.stroke1, stroke2 = each.stroke2, fill1 = each.fill1, fill2 = each.fill2; if (w1 > 0) { ctx.fillStyle = (0, _utils.hexToRGBA)(fill1, opacity); if (stroke1 !== "none") ctx.strokeStyle = stroke1; ctx.beginPath(); ctx.rect(x, y, w1, height); ctx.closePath(); ctx.fill(); if (stroke1 !== "none") ctx.stroke(); } if (w2 > 0) { ctx.fillStyle = (0, _utils.hexToRGBA)(fill2, opacity); if (stroke2 !== "none") ctx.strokeStyle = stroke2; ctx.beginPath(); ctx.rect(x + w1, y, w2, height); ctx.closePath(); ctx.fill(); if (stroke2 !== "none") ctx.stroke(); } }); } exports.default = VolumeProfileSeries; //# sourceMappingURL=VolumeProfileSeries.js.map