UNPKG

@wix/design-system

Version:

@wix/design-system

498 lines (496 loc) 19.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports["default"] = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _react = _interopRequireDefault(require("react")); var _d3Scale = require("d3-scale"); var _d3Array = require("d3-array"); var _d3Shape = require("d3-shape"); var _d3Selection = require("d3-selection"); var _d3Ease = require("d3-ease"); var _ChartTooltip = require("./ChartTooltip"); var _constants = require("./constants"); var _SparklineChartSt = require("./SparklineChart.st.css.js"); require("d3-transition"); var _Tooltip = _interopRequireDefault(require("../Tooltip")); var _Text = _interopRequireDefault(require("../Text")); var _jsxFileName = "/home/builduser/work/57e038ea7326c1ec/packages/wix-design-system/dist/cjs/SparklineChart/SparklineChart.jsx"; function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } var LINE_WIDTH = 2; var AREA_MASK_ID = 'areaMaskId'; var TOOLTIP_ELEMENT_RADIUS = 4; var DEFAULT_GRADIENT_ID = 'DEFAULT_GRADIENT_ID'; /** SparklineChart */ var SparklineChart = /*#__PURE__*/function (_React$PureComponent) { function SparklineChart(props) { var _this; (0, _classCallCheck2["default"])(this, SparklineChart); _this = _callSuper(this, SparklineChart, [props]); _this._shouldShowTooltip = function () { var hoveredLabel = _this.state.hoveredLabel; var getTooltipContent = _this.props.getTooltipContent; return getTooltipContent && typeof getTooltipContent === 'function' && hoveredLabel; }; _this._useCreateContext = function () { var halfWidth = LINE_WIDTH / 2; var _this$props = _this.props, _this$props$width = _this$props.width, width = _this$props$width === void 0 ? 200 : _this$props$width, _this$props$height = _this$props.height, height = _this$props$height === void 0 ? 40 : _this$props$height, data = _this$props.data, _this$props$highlight = _this$props.highlightedStartingIndex, highlightedStartingIndex = _this$props$highlight === void 0 ? 0 : _this$props$highlight, color = _this$props.color; var _this$props$highlight2 = _this.props.highlightedEndingIndex, highlightedEndingIndex = _this$props$highlight2 === void 0 ? data.length - 1 : _this$props$highlight2; var margin = { top: halfWidth + 2, right: halfWidth, bottom: halfWidth, left: halfWidth }; var innerTop = margin.top; var innerLeft = margin.left; var innerHeight = height - innerTop - margin.bottom; var innerWidth = width - innerLeft - margin.right; var maxValue = (0, _d3Array.max)(_this._getValues(data)); var firstLabel = _this._getLabelAt(data, 0); var lastLabel = _this._getLabelAt(data, data.length - 1); var xScale = (0, _d3Scale.scaleTime)().domain([firstLabel, lastLabel]).range([innerLeft, innerWidth]); var yScale = (0, _d3Scale.scaleLinear)().domain([0, maxValue]).range([innerHeight, innerTop]); var lineGenerator = (0, _d3Shape.line)().x(function (dataPoint, i) { return xScale(_this._getLabelAt(data, i)); }).y(function (dataPoint) { return yScale(dataPoint); }).curve(_d3Shape.curveMonotoneX); var areaGenerator = (0, _d3Shape.area)().x(function (dataPoint, i) { return xScale(_this._getLabelAt(data, i)); }).y0(function () { return innerHeight; }).y1(function (dataPoint) { return yScale(dataPoint); }).curve(_d3Shape.curveMonotoneX); return { margin: margin, width: width, height: height, innerTop: innerTop, innerLeft: innerLeft, innerBottom: margin.top + innerHeight, innerWidth: innerWidth, innerHeight: innerHeight, data: data, xScale: xScale, yScale: yScale, highlightedStartingIndex: highlightedStartingIndex, highlightedEndingIndex: highlightedEndingIndex, lineGenerator: lineGenerator, areaGenerator: areaGenerator, color: color }; }; _this._getLabelAt = function (data, position) { return data[position] && data[position].label; }; _this._getValues = function (data) { return data.map(function (pair) { return pair.value; }); }; _this._getLabels = function (data) { return data.map(function (pair) { return pair.label; }); }; _this._drawSparkline = function () { var _this$chartContext = _this.chartContext, width = _this$chartContext.width, height = _this$chartContext.height, data = _this$chartContext.data; var onHover = _this.props.onHover; var labels = _this._getLabels(data); var container = (0, _d3Selection.select)(_this.svgRef.current); container.attr('width', width).attr('height', height); var dataContainer = container.select("[data-hook=\"".concat(_constants.dataHooks.dataContainer, "\"]")); _this._drawLines(dataContainer); (0, _d3Selection.select)(_this.componentRef.current).on('mouseleave', function () { _this.setState({ hoveredLabel: null }); }).on('mousemove', function (d) { var dateUnderPointer = _this.chartContext.xScale.invert((0, _d3Selection.pointer)(d)[0]); var currentDateIndex = (0, _d3Array.bisector)(function (date) { return date; }).left(labels, dateUnderPointer, 1); var beforeDateIndex = currentDateIndex - 1; var beforeDate = labels[beforeDateIndex]; var afterDate = labels[currentDateIndex]; var closestDate = +dateUnderPointer - +beforeDate > +afterDate - +dateUnderPointer ? afterDate : beforeDate; if (typeof onHover === 'function' && !_this._areDatesEqual(closestDate, _this.state.hoveredLabel)) { var labelIndex = labels.indexOf(closestDate); onHover(labelIndex); } _this.setState({ hoveredLabel: closestDate }); }); }; _this._drawLines = function (dataContainer) { var _this$chartContext2 = _this.chartContext, data = _this$chartContext2.data, lineGenerator = _this$chartContext2.lineGenerator, areaGenerator = _this$chartContext2.areaGenerator, color = _this$chartContext2.color; var dataSets = [data]; dataContainer.selectAll('.chartLines').data(dataSets).join('g').attr('class', 'chartLines').selectAll('g').data(function (dataSet) { return [dataSet]; }).join(function (enter) { var group = enter.append('g'); group.append('path').attr('class', 'innerArea').attr('mask', "url(#".concat(_this._getAreaMaskId(_this.randomComponentId), ")")).attr('fill', function (dataSet) { return "url(#".concat(color || DEFAULT_GRADIENT_ID, ")"); }).attr('d', function (dataSet) { return areaGenerator(dataSet.map(function () { return 0; })); }); group.append('path').attr('class', 'innerLineBack').attr('data-hook', _constants.dataHooks.innerLineBack).attr('fill', 'none').attr('stroke-width', LINE_WIDTH + 4).attr('stroke-linecap', 'round').attr('d', function (dataSet) { return lineGenerator(dataSet.map(function () { return 0; })); }); group.append('path').attr('class', 'innerLine').attr('fill', 'none').attr('stroke-width', LINE_WIDTH).attr('stroke-linecap', 'round').attr('stroke', function (dataSet) { return "url(#".concat(_this._getLineColorId(dataSet, _this.randomComponentId), ")"); }).attr('d', function (dataSet) { return lineGenerator(dataSet.map(function () { return 0; })); }); _this._updateLines(group); return group; }, function (update) { _this._updateLines(update); return update; }); }; _this._updateLines = function (container) { var _this$chartContext3 = _this.chartContext, lineGenerator = _this$chartContext3.lineGenerator, areaGenerator = _this$chartContext3.areaGenerator; _this._updateComponent(container, '.innerLine', function (set) { return lineGenerator(_this._getValues(set)); }); _this._updateComponent(container, '.innerLineBack', function (set) { return lineGenerator(_this._getValues(set)); }); _this._updateComponent(container, '.innerArea', function (set) { return areaGenerator(_this._getValues(set)); }); }; _this._updateComponent = function (container, className, fncUpdater) { var animationDuration = _this.props.animationDuration; container.select(className).transition().duration(animationDuration).ease(_d3Ease.easeQuadIn).attr('d', fncUpdater); }; _this.randomComponentId = Math.random().toString(); _this.chartContext = {}; _this.svgRef = /*#__PURE__*/_react["default"].createRef(null); _this.componentRef = /*#__PURE__*/_react["default"].createRef(null); _this.state = { hoveredLabel: null }; return _this; } (0, _inherits2["default"])(SparklineChart, _React$PureComponent); return (0, _createClass2["default"])(SparklineChart, [{ key: "_getValueAt", value: function _getValueAt(data, position) { return data[position] && data[position].value; } }, { key: "_areDatesEqual", value: function _areDatesEqual(date1, date2) { var date1Time = date1 && date1.getTime(); var date2Time = date2 && date2.getTime(); return date1Time === date2Time; } }, { key: "_getLineColorId", value: function _getLineColorId(dataSet, componentId) { return "".concat(componentId, "color"); } }, { key: "_getAreaMaskId", value: function _getAreaMaskId(componentId) { return "".concat(AREA_MASK_ID).concat(componentId); } }, { key: "componentDidMount", value: function componentDidMount() { this._drawSparkline(); } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { if (prevProps.data !== this.props.data) { this._drawSparkline(); } } }, { key: "_updateContext", value: function _updateContext() { this.chartContext = this._useCreateContext(); } }, { key: "render", value: function render() { this._updateContext(); var _this$props2 = this.props, getTooltipContent = _this$props2.getTooltipContent, className = _this$props2.className, dataHook = _this$props2.dataHook; var hoveredLabel = this.state.hoveredLabel; var context = this.chartContext; var data = context.data, highlightedStartingIndex = context.highlightedStartingIndex, highlightedEndingIndex = context.highlightedEndingIndex, innerWidth = context.innerWidth, height = context.height, width = context.width, color = context.color; var highlightedStart = context.xScale(this._getLabelAt(data, highlightedStartingIndex)); var highlightedEnd = context.xScale(this._getLabelAt(data, highlightedEndingIndex)); var highlightedStartRelativeLocation = highlightedStart / innerWidth; var highlightedEndRelativeLocation = highlightedEnd / innerWidth; var labels = this._getLabels(data); var hoveredLabelIndex = (0, _d3Array.bisector)(function (d) { return d; }).left(labels, hoveredLabel, 0); var currentHoveredLabel = this._getLabelAt(data, hoveredLabelIndex); var currentHoveredValue = this._getValueAt(data, hoveredLabelIndex); var dataPoint = { content: getTooltipContent && typeof getTooltipContent === 'function' && getTooltipContent(hoveredLabelIndex), xCoordinate: context.xScale(currentHoveredLabel), yCoordinate: context.yScale(currentHoveredValue) - TOOLTIP_ELEMENT_RADIUS / 2 }; return /*#__PURE__*/_react["default"].createElement("div", { style: { width: width, height: height, position: 'relative' }, ref: this.componentRef, className: className, "data-hook": dataHook, __self: this, __source: { fileName: _jsxFileName, lineNumber: 334, columnNumber: 7 } }, /*#__PURE__*/_react["default"].createElement("svg", { style: { overflow: 'visible', zIndex: 1 }, ref: this.svgRef, __self: this, __source: { fileName: _jsxFileName, lineNumber: 340, columnNumber: 9 } }, /*#__PURE__*/_react["default"].createElement("defs", { __self: this, __source: { fileName: _jsxFileName, lineNumber: 341, columnNumber: 11 } }, /*#__PURE__*/_react["default"].createElement("mask", { id: this._getAreaMaskId(this.randomComponentId), __self: this, __source: { fileName: _jsxFileName, lineNumber: 342, columnNumber: 13 } }, /*#__PURE__*/_react["default"].createElement("rect", { x: highlightedStart, y: "0", width: highlightedEnd - highlightedStart, height: height, fill: "white", __self: this, __source: { fileName: _jsxFileName, lineNumber: 343, columnNumber: 15 } })), /*#__PURE__*/_react["default"].createElement("linearGradient", { gradientUnits: "userSpaceOnUse", key: "".concat(this.randomComponentId, "a"), id: this._getLineColorId(data, this.randomComponentId), x1: "0px", y1: "0px", x2: "".concat(innerWidth, "px"), y2: "0px", __self: this, __source: { fileName: _jsxFileName, lineNumber: 352, columnNumber: 13 } }, /*#__PURE__*/_react["default"].createElement("stop", { offset: highlightedStartRelativeLocation, style: { stopColor: '#dfe5eb', stopOpacity: 1 }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 361, columnNumber: 15 } }), /*#__PURE__*/_react["default"].createElement("stop", { offset: highlightedStartRelativeLocation, className: _SparklineChartSt.classes.gradientStop, style: { stopColor: color }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 365, columnNumber: 15 } }), /*#__PURE__*/_react["default"].createElement("stop", { offset: highlightedEndRelativeLocation, className: _SparklineChartSt.classes.gradientStop, style: { stopColor: color }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 370, columnNumber: 15 } }), /*#__PURE__*/_react["default"].createElement("stop", { offset: highlightedEndRelativeLocation, style: { stopColor: '#dfe5eb', stopOpacity: 1 }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 377, columnNumber: 15 } }), /*#__PURE__*/_react["default"].createElement("stop", { offset: 1, style: { stopColor: '#dfe5eb', stopOpacity: 1 }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 381, columnNumber: 15 } })), /*#__PURE__*/_react["default"].createElement("linearGradient", { gradientUnits: "userSpaceOnUse", key: this.randomComponentId, id: color || DEFAULT_GRADIENT_ID, x1: "0px", y1: "".concat(context.innerHeight, "px"), x2: "0px", y2: "0px", __self: this, __source: { fileName: _jsxFileName, lineNumber: 387, columnNumber: 13 } }, /*#__PURE__*/_react["default"].createElement("stop", { offset: "10%", className: _SparklineChartSt.classes.gradientStopWithoutOpacity, style: { stopColor: color }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 396, columnNumber: 15 } }), /*#__PURE__*/_react["default"].createElement("stop", { offset: "90%", className: _SparklineChartSt.classes.gradientStopWithHalfOpacity, style: { stopColor: color }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 401, columnNumber: 15 } }))), /*#__PURE__*/_react["default"].createElement("g", { __self: this, __source: { fileName: _jsxFileName, lineNumber: 410, columnNumber: 11 } }, /*#__PURE__*/_react["default"].createElement("g", { "data-hook": _constants.dataHooks.dataContainer, __self: this, __source: { fileName: _jsxFileName, lineNumber: 411, columnNumber: 13 } }), this._shouldShowTooltip() && /*#__PURE__*/_react["default"].createElement("g", { transform: "translate(".concat(dataPoint.xCoordinate, ", ").concat(dataPoint.yCoordinate + TOOLTIP_ELEMENT_RADIUS / 2, ")"), __self: this, __source: { fileName: _jsxFileName, lineNumber: 413, columnNumber: 15 } }, /*#__PURE__*/_react["default"].createElement("circle", { r: TOOLTIP_ELEMENT_RADIUS, className: _SparklineChartSt.classes.tooltipElement, fill: color, __self: this, __source: { fileName: _jsxFileName, lineNumber: 418, columnNumber: 17 } })))), this._shouldShowTooltip() && /*#__PURE__*/_react["default"].createElement(_ChartTooltip.ChartTooltip, { dataPoint: dataPoint, __self: this, __source: { fileName: _jsxFileName, lineNumber: 427, columnNumber: 39 } })); } }]); }(_react["default"].PureComponent); SparklineChart.displayName = 'SparklineChart'; SparklineChart.defaultProps = { animationDuration: 300 }; var _default = exports["default"] = SparklineChart;