UNPKG

@coinspot-official/react-stockcharts

Version:

Highly customizable stock charts with ReactJS and d3

487 lines (403 loc) 16.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 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 _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 _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 _d3Force = require("d3-force"); var _d3Array = require("d3-array"); var _GenericChartComponent = require("../GenericChartComponent"); var _GenericChartComponent2 = _interopRequireDefault(_GenericChartComponent); var _GenericComponent = require("../GenericComponent"); var _AxisZoomCapture = require("./AxisZoomCapture"); var _AxisZoomCapture2 = _interopRequireDefault(_AxisZoomCapture); var _utils = require("../utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return 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 Axis = function (_Component) { _inherits(Axis, _Component); function Axis(props) { _classCallCheck(this, Axis); var _this = _possibleConstructorReturn(this, (Axis.__proto__ || Object.getPrototypeOf(Axis)).call(this, props)); _this.drawOnCanvas = _this.drawOnCanvas.bind(_this); _this.saveNode = _this.saveNode.bind(_this); _this.getMoreProps = _this.getMoreProps.bind(_this); return _this; } _createClass(Axis, [{ key: "saveNode", value: function saveNode(node) { this.node = node; } }, { key: "getMoreProps", value: function getMoreProps() { return this.node.getMoreProps(); } }, { key: "getCachedSizesKey", value: function getCachedSizesKey() { var _this2 = this; var keyProps = ["tickPadding", "tickLabelFill", "tickStroke", "tickStrokeOpacity", "tickStrokeWidth", "orient", "showTickLabel", "fontSize", "fontFamily", "fontWeight", "showTicks", "flexTicks"]; return keyProps.map(function (prop) { return _this2.props[prop]; }).join("-"); } }, { key: "getCachedSizes", value: function getCachedSizes() { var onGetTickLabelDimensions = this.props.onGetTickLabelDimensions; if (onGetTickLabelDimensions) { var cachedSizesKey = this.getCachedSizesKey(); if (this.cachedSizesKey !== cachedSizesKey) { this.cachedSizesKey = cachedSizesKey; this.cachedSizes = {}; } } return this.cachedSizes; } }, { key: "drawOnCanvas", value: function drawOnCanvas(ctx, moreProps) { var _this3 = this; var _props = this.props, showDomain = _props.showDomain, showTicks = _props.showTicks, transform = _props.transform, range = _props.range, getScale = _props.getScale, onGetTickLabelDimensions = _props.onGetTickLabelDimensions; ctx.save(); ctx.translate(transform[0], transform[1]); if (showDomain) drawAxisLine(ctx, this.props, range); if (showTicks) { var tickProps = tickHelper(this.props, getScale(moreProps)); var measureLabels = Boolean(onGetTickLabelDimensions); this.cachedSizes = drawTicks(ctx, tickProps, this.getCachedSizes(), measureLabels); ctx.restore(); if (measureLabels) { var tickDimensions = Object.keys(this.cachedSizes).reduce(function (result, key) { var size = _this3.cachedSizes[key]; return { width: Math.max(result.width, size.width), height: Math.max(result.height, size.height) }; }, { width: 0, height: 0 }); onGetTickLabelDimensions(tickDimensions); } } else { ctx.restore(); } } }, { key: "render", value: function render() { var _props2 = this.props, bg = _props2.bg, axisZoomCallback = _props2.axisZoomCallback, className = _props2.className, zoomCursorClassName = _props2.zoomCursorClassName, zoomEnabled = _props2.zoomEnabled, getScale = _props2.getScale, inverted = _props2.inverted; var _props3 = this.props, transform = _props3.transform, getMouseDelta = _props3.getMouseDelta, edgeClip = _props3.edgeClip; var _props4 = this.props, onContextMenu = _props4.onContextMenu, onDoubleClick = _props4.onDoubleClick; var zoomCapture = zoomEnabled ? _react2.default.createElement(_AxisZoomCapture2.default, { bg: bg, getScale: getScale, getMoreProps: this.getMoreProps, getMouseDelta: getMouseDelta, axisZoomCallback: axisZoomCallback, className: className, zoomCursorClassName: zoomCursorClassName, inverted: inverted, onContextMenu: onContextMenu, onDoubleClick: onDoubleClick }) : null; return _react2.default.createElement( "g", { transform: "translate(" + transform[0] + ", " + transform[1] + ")" }, zoomCapture, _react2.default.createElement(_GenericChartComponent2.default, { ref: this.saveNode, canvasToDraw: _GenericComponent.getAxisCanvas, clip: false, edgeClip: edgeClip, canvasDraw: this.drawOnCanvas, drawOn: ["pan"] }) ); } }]); return Axis; }(_react.Component); Axis.propTypes = { innerTickSize: _propTypes2.default.number, outerTickSize: _propTypes2.default.number, tickFormat: _propTypes2.default.func, tickPadding: _propTypes2.default.number, tickSize: _propTypes2.default.number, ticks: _propTypes2.default.number, tickLabelFill: _propTypes2.default.string, tickStroke: _propTypes2.default.string, tickStrokeOpacity: _propTypes2.default.number, tickStrokeWidth: _propTypes2.default.number, tickStrokeDasharray: _propTypes2.default.oneOf(_utils.strokeDashTypes), tickValues: _propTypes2.default.oneOfType([_propTypes2.default.array, _propTypes2.default.func]), tickInterval: _propTypes2.default.number, tickIntervalFunction: _propTypes2.default.func, showDomain: _propTypes2.default.bool, showTicks: _propTypes2.default.bool, className: _propTypes2.default.string, axisZoomCallback: _propTypes2.default.func, zoomEnabled: _propTypes2.default.bool, inverted: _propTypes2.default.bool, zoomCursorClassName: _propTypes2.default.string, transform: _propTypes2.default.arrayOf(_propTypes2.default.number).isRequired, range: _propTypes2.default.arrayOf(_propTypes2.default.number).isRequired, getMouseDelta: _propTypes2.default.func.isRequired, getScale: _propTypes2.default.func.isRequired, bg: _propTypes2.default.object.isRequired, edgeClip: _propTypes2.default.bool.isRequired, onContextMenu: _propTypes2.default.func, onDoubleClick: _propTypes2.default.func, onGetTickLabelDimensions: _propTypes2.default.func }; Axis.defaultProps = { zoomEnabled: false, zoomCursorClassName: "", edgeClip: false }; function tickHelper(props, scale) { var orient = props.orient, innerTickSize = props.innerTickSize, tickFormat = props.tickFormat, tickPadding = props.tickPadding, tickLabelFill = props.tickLabelFill, tickStrokeWidth = props.tickStrokeWidth, tickStrokeDasharray = props.tickStrokeDasharray, fontSize = props.fontSize, fontFamily = props.fontFamily, fontWeight = props.fontWeight, showTicks = props.showTicks, flexTicks = props.flexTicks, showTickLabel = props.showTickLabel; var tickArguments = props.ticks, tickValuesProp = props.tickValues, tickStroke = props.tickStroke, tickStrokeOpacity = props.tickStrokeOpacity, tickInterval = props.tickInterval, tickIntervalFunction = props.tickIntervalFunction; // if (tickArguments) tickArguments = [tickArguments]; var tickValues = void 0; if ((0, _utils.isDefined)(tickValuesProp)) { if (typeof tickValuesProp === "function") { tickValues = tickValuesProp(scale.domain()); } else { tickValues = tickValuesProp; } } else if ((0, _utils.isDefined)(tickInterval)) { var _scale$domain = scale.domain(), _scale$domain2 = _slicedToArray(_scale$domain, 2), min = _scale$domain2[0], max = _scale$domain2[1]; var baseTickValues = (0, _d3Array.range)(min, max, (max - min) / tickInterval); tickValues = tickIntervalFunction ? tickIntervalFunction(min, max, tickInterval) : baseTickValues; } else if ((0, _utils.isDefined)(scale.ticks)) { tickValues = scale.ticks(tickArguments, flexTicks); } else { tickValues = scale.domain(); } var baseFormat = scale.tickFormat ? scale.tickFormat(tickArguments) : _utils.identity; var format = (0, _utils.isNotDefined)(tickFormat) ? baseFormat : function (d) { return tickFormat(d) || ""; }; var sign = orient === "top" || orient === "left" ? -1 : 1; var tickSpacing = Math.max(innerTickSize, 0) + tickPadding; var ticks = void 0, dy = void 0, canvas_dy = void 0, textAnchor = void 0; if (orient === "bottom" || orient === "top") { dy = sign < 0 ? "0em" : ".71em"; canvas_dy = sign < 0 ? 0 : fontSize * .71; textAnchor = "middle"; ticks = tickValues.map(function (d) { var x = Math.round(scale(d)); return { value: d, x1: x, y1: 0, x2: x, y2: sign * innerTickSize, labelX: x, labelY: sign * tickSpacing }; }); if (showTicks && flexTicks) { // console.log(ticks, showTicks); var nodes = ticks.map(function (d) { return { id: d.value, value: d.value, fy: d.y2, origX: d.x1 }; }); var simulation = (0, _d3Force.forceSimulation)(nodes).force("x", (0, _d3Force.forceX)(function (d) { return d.origX; }).strength(1)).force("collide", (0, _d3Force.forceCollide)(22)) // .force("center", forceCenter()) .stop(); for (var i = 0; i < 100; ++i) { simulation.tick(); } // console.log(nodes); var zip = (0, _utils.zipper)().combine(function (a, b) { if (Math.abs(b.x - b.origX) > 0.01) { return _extends({}, a, { x2: b.x, labelX: b.x }); } return a; }); ticks = zip(ticks, nodes); } } else { ticks = tickValues.map(function (d) { var y = Math.round(scale(d)); return { value: d, x1: 0, y1: y, x2: sign * innerTickSize, y2: y, labelX: sign * tickSpacing, labelY: y }; }); dy = ".32em"; canvas_dy = fontSize * .32; textAnchor = sign < 0 ? "end" : "start"; } return { ticks: ticks, scale: scale, tickStroke: tickStroke, tickLabelFill: tickLabelFill || tickStroke, tickStrokeOpacity: tickStrokeOpacity, tickStrokeWidth: tickStrokeWidth, tickStrokeDasharray: tickStrokeDasharray, dy: dy, canvas_dy: canvas_dy, textAnchor: textAnchor, fontSize: fontSize, fontFamily: fontFamily, fontWeight: fontWeight, format: format, showTickLabel: showTickLabel, tickSpacing: tickSpacing }; } function drawAxisLine(ctx, props, range) { // props = { ...AxisLine.defaultProps, ...props }; var orient = props.orient, outerTickSize = props.outerTickSize, stroke = props.stroke, strokeWidth = props.strokeWidth, opacity = props.opacity; var sign = orient === "top" || orient === "left" ? -1 : 1; var xAxis = orient === "bottom" || orient === "top"; // var range = d3_scaleRange(xAxis ? xScale : yScale); ctx.lineWidth = strokeWidth; ctx.strokeStyle = (0, _utils.hexToRGBA)(stroke, opacity); ctx.beginPath(); if (xAxis) { ctx.moveTo((0, _utils.first)(range), sign * outerTickSize); ctx.lineTo((0, _utils.first)(range), 0); ctx.lineTo((0, _utils.last)(range), 0); ctx.lineTo((0, _utils.last)(range), sign * outerTickSize); } else { ctx.moveTo(sign * outerTickSize, (0, _utils.first)(range)); ctx.lineTo(0, (0, _utils.first)(range)); ctx.lineTo(0, (0, _utils.last)(range)); ctx.lineTo(sign * outerTickSize, (0, _utils.last)(range)); } ctx.stroke(); } function drawTicks(ctx, result, cachedSizes, measureLabels) { var tickStroke = result.tickStroke, tickStrokeOpacity = result.tickStrokeOpacity, tickLabelFill = result.tickLabelFill; var textAnchor = result.textAnchor, fontSize = result.fontSize, fontFamily = result.fontFamily, fontWeight = result.fontWeight, ticks = result.ticks, showTickLabel = result.showTickLabel; ctx.strokeStyle = (0, _utils.hexToRGBA)(tickStroke, tickStrokeOpacity); ctx.fillStyle = tickStroke; // ctx.textBaseline = 'middle'; ticks.forEach(function (tick) { drawEachTick(ctx, tick, result); }); ctx.font = fontWeight + " " + fontSize + "px " + fontFamily; ctx.fillStyle = tickLabelFill; ctx.textAlign = textAnchor === "middle" ? "center" : textAnchor; if (showTickLabel) { return ticks.reduce(function (newCachedSizes, tick) { var newSize = drawEachTickLabel(ctx, tick, result, cachedSizes, measureLabels); return _extends({}, newCachedSizes, newSize); }, {}); } return cachedSizes; } function drawEachTick(ctx, tick, result) { var tickStrokeWidth = result.tickStrokeWidth, tickStrokeDasharray = result.tickStrokeDasharray; ctx.beginPath(); ctx.moveTo(tick.x1, tick.y1); ctx.lineTo(tick.x2, tick.y2); ctx.lineWidth = tickStrokeWidth; ctx.setLineDash((0, _utils.getStrokeDasharray)(tickStrokeDasharray).split(",")); ctx.stroke(); } function drawEachTickLabel(ctx, tick, result, cachedSizes, measureLabels) { var orient = result.orient, canvas_dy = result.canvas_dy, format = result.format, fontSize = result.fontSize, tickSpacing = result.tickSpacing; var xAxis = orient === "bottom" || orient === "top"; var text = format(tick.value); ctx.beginPath(); ctx.fillText(text, tick.labelX, tick.labelY + canvas_dy); if (measureLabels) { if (cachedSizes[text]) { return { text: cachedSizes[text] }; } else { var _ctx$measureText = ctx.measureText(text), width = _ctx$measureText.width; var widthSpacing = xAxis ? 0 : tickSpacing; var heightSpacing = xAxis ? tickSpacing : 0; return _defineProperty({}, text, { width: widthSpacing + width, height: heightSpacing + fontSize }); } } else { return {}; } } exports.default = Axis; //# sourceMappingURL=Axis.js.map