UNPKG

react-vis

Version:

Data visualization library based on React and d3.

426 lines (369 loc) 15 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 _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 _abstractSeries = require('./series/abstract-series'); var _abstractSeries2 = _interopRequireDefault(_abstractSeries); var _scalesUtils = require('../utils/scales-utils'); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); 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; } function getLocs(evt) { var xLoc = evt.type === 'touchstart' ? evt.pageX : evt.offsetX; var yLoc = evt.type === 'touchstart' ? evt.pageY : evt.offsetY; return { xLoc: xLoc, yLoc: yLoc }; } var Highlight = function (_AbstractSeries) { _inherits(Highlight, _AbstractSeries); function Highlight() { var _ref; var _temp, _this, _ret; _classCallCheck(this, Highlight); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Highlight.__proto__ || Object.getPrototypeOf(Highlight)).call.apply(_ref, [this].concat(args))), _this), _this.state = { dragging: false, brushArea: { top: 0, right: 0, bottom: 0, left: 0 }, brushing: false, startLocX: 0, startLocY: 0, dragArea: null }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(Highlight, [{ key: '_getDrawArea', value: function _getDrawArea(xLoc, yLoc) { var _state = this.state, startLocX = _state.startLocX, startLocY = _state.startLocY; var _props = this.props, enableX = _props.enableX, enableY = _props.enableY, highlightWidth = _props.highlightWidth, highlightHeight = _props.highlightHeight, innerWidth = _props.innerWidth, innerHeight = _props.innerHeight, marginLeft = _props.marginLeft, marginRight = _props.marginRight, marginBottom = _props.marginBottom, marginTop = _props.marginTop; var plotHeight = innerHeight + marginTop + marginBottom; var plotWidth = innerWidth + marginLeft + marginRight; var touchWidth = highlightWidth || plotWidth; var touchHeight = highlightHeight || plotHeight; return { bottom: enableY ? Math.max(startLocY, yLoc) : touchHeight, right: enableX ? Math.max(startLocX, xLoc) : touchWidth, left: enableX ? Math.min(xLoc, startLocX) : 0, top: enableY ? Math.min(yLoc, startLocY) : 0 }; } }, { key: '_getDragArea', value: function _getDragArea(xLoc, yLoc) { var _props2 = this.props, enableX = _props2.enableX, enableY = _props2.enableY; var _state2 = this.state, startLocX = _state2.startLocX, startLocY = _state2.startLocY, dragArea = _state2.dragArea; return { bottom: dragArea.bottom + (enableY ? yLoc - startLocY : 0), left: dragArea.left + (enableX ? xLoc - startLocX : 0), right: dragArea.right + (enableX ? xLoc - startLocX : 0), top: dragArea.top + (enableY ? yLoc - startLocY : 0) }; } }, { key: '_clickedOutsideDrag', value: function _clickedOutsideDrag(xLoc, yLoc) { var _props3 = this.props, enableX = _props3.enableX, enableY = _props3.enableY; var _state3 = this.state, dragArea = _state3.dragArea, _state3$brushArea = _state3.brushArea, left = _state3$brushArea.left, right = _state3$brushArea.right, top = _state3$brushArea.top, bottom = _state3$brushArea.bottom; var clickedOutsideDragX = dragArea && (xLoc < left || xLoc > right); var clickedOutsideDragY = dragArea && (yLoc < top || yLoc > bottom); if (enableX && enableY) { return clickedOutsideDragX || clickedOutsideDragY; } if (enableX) { return clickedOutsideDragX; } if (enableY) { return clickedOutsideDragY; } return true; } }, { key: '_convertAreaToCoordinates', value: function _convertAreaToCoordinates(brushArea) { // NOTE only continuous scales are supported for brushing/getting coordinates back var _props4 = this.props, enableX = _props4.enableX, enableY = _props4.enableY, marginLeft = _props4.marginLeft, marginTop = _props4.marginTop; var xScale = (0, _scalesUtils.getAttributeScale)(this.props, 'x'); var yScale = (0, _scalesUtils.getAttributeScale)(this.props, 'y'); // Ensure that users wishes are being respected about which scales are evaluated // this is specifically enabled to ensure brushing on mixed categorical and linear // charts will run as expected if (enableX && enableY) { return { bottom: yScale.invert(brushArea.bottom), left: xScale.invert(brushArea.left - marginLeft), right: xScale.invert(brushArea.right - marginLeft), top: yScale.invert(brushArea.top) }; } if (enableY) { return { bottom: yScale.invert(brushArea.bottom - marginTop), top: yScale.invert(brushArea.top - marginTop) }; } if (enableX) { return { left: xScale.invert(brushArea.left - marginLeft), right: xScale.invert(brushArea.right - marginLeft) }; } return {}; } }, { key: 'startBrushing', value: function startBrushing(e) { var _this2 = this; var _props5 = this.props, onBrushStart = _props5.onBrushStart, onDragStart = _props5.onDragStart, drag = _props5.drag; var dragArea = this.state.dragArea; var _getLocs = getLocs(e.nativeEvent), xLoc = _getLocs.xLoc, yLoc = _getLocs.yLoc; var startArea = function startArea(dragging, resetDrag) { var emptyBrush = { bottom: yLoc, left: xLoc, right: xLoc, top: yLoc }; _this2.setState({ dragging: dragging, brushArea: dragArea && !resetDrag ? dragArea : emptyBrush, brushing: !dragging, startLocX: xLoc, startLocY: yLoc }); }; var clickedOutsideDrag = this._clickedOutsideDrag(xLoc, yLoc); if (drag && !dragArea || !drag || clickedOutsideDrag) { startArea(false, clickedOutsideDrag); if (onBrushStart) { onBrushStart(e); } return; } if (drag && dragArea) { startArea(true, clickedOutsideDrag); if (onDragStart) { onDragStart(e); } } } }, { key: 'stopBrushing', value: function stopBrushing(e) { var _state4 = this.state, brushing = _state4.brushing, dragging = _state4.dragging, brushArea = _state4.brushArea; // Quickly short-circuit if the user isn't brushing in our component if (!brushing && !dragging) { return; } var _props6 = this.props, onBrushEnd = _props6.onBrushEnd, onDragEnd = _props6.onDragEnd, drag = _props6.drag; var noHorizontal = Math.abs(brushArea.right - brushArea.left) < 5; var noVertical = Math.abs(brushArea.top - brushArea.bottom) < 5; // Invoke the callback with null if the selected area was < 5px var isNulled = noVertical || noHorizontal; // Clear the draw area this.setState({ brushing: false, dragging: false, brushArea: drag ? brushArea : { top: 0, right: 0, bottom: 0, left: 0 }, startLocX: 0, startLocY: 0, dragArea: drag && !isNulled && brushArea }); if (brushing && onBrushEnd) { onBrushEnd(!isNulled ? this._convertAreaToCoordinates(brushArea) : null); } if (drag && onDragEnd) { onDragEnd(!isNulled ? this._convertAreaToCoordinates(brushArea) : null); } } }, { key: 'onBrush', value: function onBrush(e) { var _props7 = this.props, onBrush = _props7.onBrush, onDrag = _props7.onDrag, drag = _props7.drag; var _state5 = this.state, brushing = _state5.brushing, dragging = _state5.dragging; var _getLocs2 = getLocs(e.nativeEvent), xLoc = _getLocs2.xLoc, yLoc = _getLocs2.yLoc; if (brushing) { var brushArea = this._getDrawArea(xLoc, yLoc); this.setState({ brushArea: brushArea }); if (onBrush) { onBrush(this._convertAreaToCoordinates(brushArea)); } } if (drag && dragging) { var _brushArea = this._getDragArea(xLoc, yLoc); this.setState({ brushArea: _brushArea }); if (onDrag) { onDrag(this._convertAreaToCoordinates(_brushArea)); } } } }, { key: 'render', value: function render() { var _this3 = this; var _props8 = this.props, color = _props8.color, className = _props8.className, highlightHeight = _props8.highlightHeight, highlightWidth = _props8.highlightWidth, highlightX = _props8.highlightX, highlightY = _props8.highlightY, innerWidth = _props8.innerWidth, innerHeight = _props8.innerHeight, marginLeft = _props8.marginLeft, marginRight = _props8.marginRight, marginTop = _props8.marginTop, marginBottom = _props8.marginBottom, opacity = _props8.opacity; var _state$brushArea = this.state.brushArea, left = _state$brushArea.left, right = _state$brushArea.right, top = _state$brushArea.top, bottom = _state$brushArea.bottom; var leftPos = 0; if (highlightX) { var xScale = (0, _scalesUtils.getAttributeScale)(this.props, 'x'); leftPos = xScale(highlightX); } var topPos = 0; if (highlightY) { var yScale = (0, _scalesUtils.getAttributeScale)(this.props, 'y'); topPos = yScale(highlightY); } var plotWidth = marginLeft + marginRight + innerWidth; var plotHeight = marginTop + marginBottom + innerHeight; var touchWidth = highlightWidth || plotWidth; var touchHeight = highlightHeight || plotHeight; return _react2.default.createElement( 'g', { transform: 'translate(' + leftPos + ', ' + topPos + ')', className: className + ' rv-highlight-container' }, _react2.default.createElement('rect', { className: 'rv-mouse-target', fill: 'black', opacity: '0', x: '0', y: '0', width: Math.max(touchWidth, 0), height: Math.max(touchHeight, 0), onMouseDown: function onMouseDown(e) { return _this3.startBrushing(e); }, onMouseMove: function onMouseMove(e) { return _this3.onBrush(e); }, onMouseUp: function onMouseUp(e) { return _this3.stopBrushing(e); }, onMouseLeave: function onMouseLeave(e) { return _this3.stopBrushing(e); } // preventDefault() so that mouse event emulation does not happen , onTouchEnd: function onTouchEnd(e) { e.preventDefault(); _this3.stopBrushing(e); }, onTouchCancel: function onTouchCancel(e) { e.preventDefault(); _this3.stopBrushing(e); }, onContextMenu: function onContextMenu(e) { return e.preventDefault(); }, onContextMenuCapture: function onContextMenuCapture(e) { return e.preventDefault(); } }), _react2.default.createElement('rect', { className: 'rv-highlight', pointerEvents: 'none', opacity: opacity, fill: color, x: left, y: top, width: Math.min(Math.max(0, right - left), touchWidth), height: Math.min(Math.max(0, bottom - top), touchHeight) }) ); } }]); return Highlight; }(_abstractSeries2.default); Highlight.displayName = 'HighlightOverlay'; Highlight.defaultProps = { color: 'rgb(77, 182, 172)', className: '', enableX: true, enableY: true, opacity: 0.3 }; Highlight.propTypes = _extends({}, _abstractSeries2.default.propTypes, { enableX: _propTypes2.default.bool, enableY: _propTypes2.default.bool, highlightHeight: _propTypes2.default.number, highlightWidth: _propTypes2.default.number, highlightX: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]), highlightY: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]), onBrushStart: _propTypes2.default.func, onDragStart: _propTypes2.default.func, onBrush: _propTypes2.default.func, onDrag: _propTypes2.default.func, onBrushEnd: _propTypes2.default.func, onDragEnd: _propTypes2.default.func }); exports.default = Highlight;