wix-style-react
Version:
464 lines (404 loc) • 18.5 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
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 _colorsSt = require("../Foundation/stylable/colors.st.css");
require("d3-transition");
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
var LINE_WIDTH = 2;
var AREA_MASK_ID = 'areaMaskId';
var TOOLTIP_ELEMENT_RADIUS = 4;
var DEFAULT_COLOR = _colorsSt.stVars.A1;
/** SparklineChart */
var SparklineChart = /*#__PURE__*/function (_React$PureComponent) {
(0, _inherits2["default"])(SparklineChart, _React$PureComponent);
var _super = _createSuper(SparklineChart);
function SparklineChart(props) {
var _this;
(0, _classCallCheck2["default"])(this, SparklineChart);
_this = _super.call(this, props);
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_shouldShowTooltip", function () {
var hoveredLabel = _this.state.hoveredLabel;
var getTooltipContent = _this.props.getTooltipContent;
return getTooltipContent && typeof getTooltipContent === 'function' && hoveredLabel;
});
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_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,
_this$props$color = _this$props.color,
color = _this$props$color === void 0 ? DEFAULT_COLOR : _this$props$color;
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,
lineGenerator: lineGenerator,
areaGenerator: areaGenerator,
color: color
};
});
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_getLabelAt", function (data, position) {
return data[position] && data[position].label;
});
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_getValues", function (data) {
return data.map(function (pair) {
return pair.value;
});
});
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_getLabels", function (data) {
return data.map(function (pair) {
return pair.label;
});
});
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_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
});
});
});
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_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, ")");
}).attr('d', function (dataSet) {
return areaGenerator(dataSet.map(function () {
return 0;
}));
});
group.append('path').attr('class', 'innerLineBack').attr('fill', 'none').attr('stroke-width', LINE_WIDTH + 4).attr('stroke-linecap', 'round').attr('stroke', 'white').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;
});
});
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_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));
});
});
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_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, _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,
innerWidth = context.innerWidth,
height = context.height,
width = context.width,
color = context.color;
var highlightedStartBefore = context.xScale(this._getLabelAt(data, highlightedStartingIndex - 1));
var highlightedStart = context.xScale(this._getLabelAt(data, highlightedStartingIndex));
var highlightedRelativeLocation = highlightedStart / innerWidth;
var inter = (highlightedStart - highlightedStartBefore) / 2 / 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
};
var enableHighlightedAreaEffect = highlightedStartingIndex > 0;
return /*#__PURE__*/_react["default"].createElement("div", {
style: {
width: width,
height: height,
position: 'relative'
},
ref: this.componentRef,
className: className,
"data-hook": dataHook
}, /*#__PURE__*/_react["default"].createElement("svg", {
style: {
overflow: 'visible',
zIndex: 1
},
ref: this.svgRef
}, /*#__PURE__*/_react["default"].createElement("defs", null, /*#__PURE__*/_react["default"].createElement("mask", {
id: this._getAreaMaskId(this.randomComponentId)
}, /*#__PURE__*/_react["default"].createElement("rect", {
x: highlightedStart,
y: "0",
width: width,
height: height,
fill: "white"
})), /*#__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'
}, enableHighlightedAreaEffect && [/*#__PURE__*/_react["default"].createElement("stop", {
key: 0,
offset: "0",
style: {
stopColor: '#dfe5eb',
stopOpacity: 1
}
}), /*#__PURE__*/_react["default"].createElement("stop", {
key: 1,
offset: highlightedRelativeLocation - inter,
style: {
stopColor: '#dfe5eb',
stopOpacity: 1
}
}), /*#__PURE__*/_react["default"].createElement("stop", {
key: 2,
offset: highlightedRelativeLocation,
style: {
stopColor: color,
stopOpacity: 1
}
})], /*#__PURE__*/_react["default"].createElement("stop", {
offset: "1",
style: {
stopColor: color,
stopOpacity: 1
}
})), /*#__PURE__*/_react["default"].createElement("linearGradient", {
gradientUnits: 'userSpaceOnUse',
key: this.randomComponentId,
id: color,
x1: "0px",
y1: "".concat(context.innerHeight, "px"),
x2: "0px",
y2: '0px'
}, /*#__PURE__*/_react["default"].createElement("stop", {
offset: "10%",
style: {
stopColor: color,
stopOpacity: 0
}
}), /*#__PURE__*/_react["default"].createElement("stop", {
offset: "90%",
style: {
stopColor: color,
stopOpacity: 0.5
}
}))), /*#__PURE__*/_react["default"].createElement("g", null, /*#__PURE__*/_react["default"].createElement("g", {
"data-hook": _constants.dataHooks.dataContainer
}), this._shouldShowTooltip() && /*#__PURE__*/_react["default"].createElement("g", {
transform: "translate(".concat(dataPoint.xCoordinate, ", ").concat(dataPoint.yCoordinate + TOOLTIP_ELEMENT_RADIUS / 2, ")")
}, /*#__PURE__*/_react["default"].createElement("circle", {
r: TOOLTIP_ELEMENT_RADIUS,
fill: color
})))), this._shouldShowTooltip() && /*#__PURE__*/_react["default"].createElement(_ChartTooltip.ChartTooltip, {
dataPoint: dataPoint
}));
}
}]);
return SparklineChart;
}(_react["default"].PureComponent);
SparklineChart.displayName = 'SparklineChart';
SparklineChart.propTypes = {
/** Applied as data-hook HTML attribute that can be used in the tests */
dataHook: _propTypes["default"].string,
/** A css class to be applied to the component's root element */
className: _propTypes["default"].string,
/** Sets the width of the sparkline (pixels) */
width: _propTypes["default"].number,
/** Sets the height of the sparkline (pixels) */
height: _propTypes["default"].number,
/** Chart data */
data: _propTypes["default"].arrayOf(_propTypes["default"].shape({
label: _propTypes["default"].instanceOf(Date),
value: _propTypes["default"].number
})).isRequired,
/** Sets the color of the sparkline */
color: _propTypes["default"].string,
/** Indicates the starting index of the highlighted area. Default is 0 */
highlightedStartingIndex: _propTypes["default"].number,
/** Tooltip content (JSX) getter function. */
getTooltipContent: _propTypes["default"].func,
/** callback when graph is hovered*/
onHover: _propTypes["default"].func,
/** Sets the duration of the animation in milliseconds */
animationDuration: _propTypes["default"].number
};
SparklineChart.defaultProps = {
animationDuration: 300
};
var _default = SparklineChart;
exports["default"] = _default;