source: node_modules/recharts/es6/cartesian/Brush.js

Last change on this file was a762898, checked in by istevanoska <ilinastevanoska@…>, 5 months ago

Added visualizations

  • Property mode set to 100644
File size: 26.7 KB
Line 
1function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
6function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7import * as React from 'react';
8import { Children, PureComponent, useCallback, useContext, useEffect } from 'react';
9import { clsx } from 'clsx';
10import { scalePoint } from 'victory-vendor/d3-scale';
11import range from 'es-toolkit/compat/range';
12import { Layer } from '../container/Layer';
13import { Text } from '../component/Text';
14import { getValueByDataKey } from '../util/ChartUtils';
15import { isNumber, isNotNil } from '../util/DataUtils';
16import { generatePrefixStyle } from '../util/CssPrefixUtils';
17import { useChartData, useDataIndex } from '../context/chartDataContext';
18import { BrushUpdateDispatchContext } from '../context/brushUpdateContext';
19import { useAppDispatch, useAppSelector } from '../state/hooks';
20import { setDataStartEndIndexes } from '../state/chartDataSlice';
21import { setBrushSettings } from '../state/brushSlice';
22import { PanoramaContextProvider } from '../context/PanoramaContext';
23import { selectBrushDimensions } from '../state/selectors/brushSelectors';
24import { useBrushChartSynchronisation } from '../synchronisation/useChartSynchronisation';
25import { resolveDefaultProps } from '../util/resolveDefaultProps';
26import { svgPropertiesNoEvents } from '../util/svgPropertiesNoEvents';
27
28// Why is this tickFormatter different from the other TickFormatters? This one allows to return numbers too for some reason.
29
30function DefaultTraveller(props) {
31 var {
32 x,
33 y,
34 width,
35 height,
36 stroke
37 } = props;
38 var lineY = Math.floor(y + height / 2) - 1;
39 return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
40 x: x,
41 y: y,
42 width: width,
43 height: height,
44 fill: stroke,
45 stroke: "none"
46 }), /*#__PURE__*/React.createElement("line", {
47 x1: x + 1,
48 y1: lineY,
49 x2: x + width - 1,
50 y2: lineY,
51 fill: "none",
52 stroke: "#fff"
53 }), /*#__PURE__*/React.createElement("line", {
54 x1: x + 1,
55 y1: lineY + 2,
56 x2: x + width - 1,
57 y2: lineY + 2,
58 fill: "none",
59 stroke: "#fff"
60 }));
61}
62function Traveller(props) {
63 var {
64 travellerProps,
65 travellerType
66 } = props;
67 if (/*#__PURE__*/React.isValidElement(travellerType)) {
68 // @ts-expect-error element cloning disagrees with the types (and it should)
69 return /*#__PURE__*/React.cloneElement(travellerType, travellerProps);
70 }
71 if (typeof travellerType === 'function') {
72 return travellerType(travellerProps);
73 }
74 return /*#__PURE__*/React.createElement(DefaultTraveller, travellerProps);
75}
76function getNameFromUnknown(value) {
77 if (isNotNil(value) && typeof value === 'object' && 'name' in value && typeof value.name === 'string') {
78 return value.name;
79 }
80 return undefined;
81}
82function getAriaLabel(data, startIndex, endIndex) {
83 var start = getNameFromUnknown(data[startIndex]);
84 var end = getNameFromUnknown(data[endIndex]);
85 return "Min value: ".concat(start, ", Max value: ").concat(end);
86}
87function TravellerLayer(_ref) {
88 var {
89 otherProps,
90 travellerX,
91 id,
92 onMouseEnter,
93 onMouseLeave,
94 onMouseDown,
95 onTouchStart,
96 onTravellerMoveKeyboard,
97 onFocus,
98 onBlur
99 } = _ref;
100 var {
101 y,
102 x: xFromProps,
103 travellerWidth,
104 height,
105 traveller,
106 ariaLabel,
107 data,
108 startIndex,
109 endIndex
110 } = otherProps;
111 var x = Math.max(travellerX, xFromProps);
112 var travellerProps = _objectSpread(_objectSpread({}, svgPropertiesNoEvents(otherProps)), {}, {
113 x,
114 y,
115 width: travellerWidth,
116 height
117 });
118 var ariaLabelBrush = ariaLabel || getAriaLabel(data, startIndex, endIndex);
119 return /*#__PURE__*/React.createElement(Layer, {
120 tabIndex: 0,
121 role: "slider",
122 "aria-label": ariaLabelBrush,
123 "aria-valuenow": travellerX,
124 className: "recharts-brush-traveller",
125 onMouseEnter: onMouseEnter,
126 onMouseLeave: onMouseLeave,
127 onMouseDown: onMouseDown,
128 onTouchStart: onTouchStart,
129 onKeyDown: e => {
130 if (!['ArrowLeft', 'ArrowRight'].includes(e.key)) {
131 return;
132 }
133 e.preventDefault();
134 e.stopPropagation();
135 onTravellerMoveKeyboard(e.key === 'ArrowRight' ? 1 : -1, id);
136 },
137 onFocus: onFocus,
138 onBlur: onBlur,
139 style: {
140 cursor: 'col-resize'
141 }
142 }, /*#__PURE__*/React.createElement(Traveller, {
143 travellerType: traveller,
144 travellerProps: travellerProps
145 }));
146}
147/*
148 * This one cannot be a React Component because React is not happy with it returning only string | number.
149 * React wants a full React.JSX.Element but that is not compatible with Text component.
150 */
151function getTextOfTick(props) {
152 var {
153 index,
154 data,
155 tickFormatter,
156 dataKey
157 } = props;
158 // @ts-expect-error getValueByDataKey does not validate the output type
159 var text = getValueByDataKey(data[index], dataKey, index);
160 return typeof tickFormatter === 'function' ? tickFormatter(text, index) : text;
161}
162function getIndexInRange(valueRange, x) {
163 var len = valueRange.length;
164 var start = 0;
165 var end = len - 1;
166 while (end - start > 1) {
167 var middle = Math.floor((start + end) / 2);
168 var middleValue = valueRange[middle];
169 if (middleValue != null && middleValue > x) {
170 end = middle;
171 } else {
172 start = middle;
173 }
174 }
175 var endValue = valueRange[end];
176 return endValue != null && x >= endValue ? end : start;
177}
178function getIndex(_ref2) {
179 var {
180 startX,
181 endX,
182 scaleValues,
183 gap,
184 data
185 } = _ref2;
186 var lastIndex = data.length - 1;
187 var min = Math.min(startX, endX);
188 var max = Math.max(startX, endX);
189 var minIndex = getIndexInRange(scaleValues, min);
190 var maxIndex = getIndexInRange(scaleValues, max);
191 return {
192 startIndex: minIndex - minIndex % gap,
193 endIndex: maxIndex === lastIndex ? lastIndex : maxIndex - maxIndex % gap
194 };
195}
196function Background(_ref3) {
197 var {
198 x,
199 y,
200 width,
201 height,
202 fill,
203 stroke
204 } = _ref3;
205 return /*#__PURE__*/React.createElement("rect", {
206 stroke: stroke,
207 fill: fill,
208 x: x,
209 y: y,
210 width: width,
211 height: height
212 });
213}
214function BrushText(_ref4) {
215 var {
216 startIndex,
217 endIndex,
218 y,
219 height,
220 travellerWidth,
221 stroke,
222 tickFormatter,
223 dataKey,
224 data,
225 startX,
226 endX
227 } = _ref4;
228 var offset = 5;
229 var attrs = {
230 pointerEvents: 'none',
231 fill: stroke
232 };
233 return /*#__PURE__*/React.createElement(Layer, {
234 className: "recharts-brush-texts"
235 }, /*#__PURE__*/React.createElement(Text, _extends({
236 textAnchor: "end",
237 verticalAnchor: "middle",
238 x: Math.min(startX, endX) - offset,
239 y: y + height / 2
240 }, attrs), getTextOfTick({
241 index: startIndex,
242 tickFormatter,
243 dataKey,
244 data
245 })), /*#__PURE__*/React.createElement(Text, _extends({
246 textAnchor: "start",
247 verticalAnchor: "middle",
248 x: Math.max(startX, endX) + travellerWidth + offset,
249 y: y + height / 2
250 }, attrs), getTextOfTick({
251 index: endIndex,
252 tickFormatter,
253 dataKey,
254 data
255 })));
256}
257function Slide(_ref5) {
258 var {
259 y,
260 height,
261 stroke,
262 travellerWidth,
263 startX,
264 endX,
265 onMouseEnter,
266 onMouseLeave,
267 onMouseDown,
268 onTouchStart
269 } = _ref5;
270 var x = Math.min(startX, endX) + travellerWidth;
271 var width = Math.max(Math.abs(endX - startX) - travellerWidth, 0);
272 return /*#__PURE__*/React.createElement("rect", {
273 className: "recharts-brush-slide",
274 onMouseEnter: onMouseEnter,
275 onMouseLeave: onMouseLeave,
276 onMouseDown: onMouseDown,
277 onTouchStart: onTouchStart,
278 style: {
279 cursor: 'move'
280 },
281 stroke: "none",
282 fill: stroke,
283 fillOpacity: 0.2,
284 x: x,
285 y: y,
286 width: width,
287 height: height
288 });
289}
290function Panorama(_ref6) {
291 var {
292 x,
293 y,
294 width,
295 height,
296 data,
297 children,
298 padding
299 } = _ref6;
300 var isPanoramic = React.Children.count(children) === 1;
301 if (!isPanoramic) {
302 return null;
303 }
304 var chartElement = Children.only(children);
305 if (!chartElement) {
306 return null;
307 }
308 return /*#__PURE__*/React.cloneElement(chartElement, {
309 x,
310 y,
311 width,
312 height,
313 margin: padding,
314 compact: true,
315 data
316 });
317}
318var createScale = _ref7 => {
319 var {
320 data,
321 startIndex,
322 endIndex,
323 x,
324 width,
325 travellerWidth
326 } = _ref7;
327 if (!data || !data.length) {
328 return {};
329 }
330 var len = data.length;
331 var scale = scalePoint().domain(range(0, len)).range([x, x + width - travellerWidth]);
332 var scaleValues = scale.domain().map(entry => scale(entry)).filter(isNotNil);
333 return {
334 isTextActive: false,
335 isSlideMoving: false,
336 isTravellerMoving: false,
337 isTravellerFocused: false,
338 startX: scale(startIndex),
339 endX: scale(endIndex),
340 scale,
341 scaleValues
342 };
343};
344var isTouch = e => e.changedTouches && !!e.changedTouches.length;
345class BrushWithState extends PureComponent {
346 constructor(props) {
347 super(props);
348 _defineProperty(this, "handleDrag", e => {
349 if (this.leaveTimer) {
350 clearTimeout(this.leaveTimer);
351 this.leaveTimer = null;
352 }
353 if (this.state.isTravellerMoving) {
354 this.handleTravellerMove(e);
355 } else if (this.state.isSlideMoving) {
356 this.handleSlideDrag(e);
357 }
358 });
359 _defineProperty(this, "handleTouchMove", e => {
360 var _e$changedTouches;
361 var touch = (_e$changedTouches = e.changedTouches) === null || _e$changedTouches === void 0 ? void 0 : _e$changedTouches[0];
362 if (touch != null) {
363 this.handleDrag(touch);
364 }
365 });
366 _defineProperty(this, "handleDragEnd", () => {
367 this.setState({
368 isTravellerMoving: false,
369 isSlideMoving: false
370 }, () => {
371 var {
372 endIndex,
373 onDragEnd,
374 startIndex
375 } = this.props;
376 onDragEnd === null || onDragEnd === void 0 || onDragEnd({
377 endIndex,
378 startIndex
379 });
380 });
381 this.detachDragEndListener();
382 });
383 _defineProperty(this, "handleLeaveWrapper", () => {
384 if (this.state.isTravellerMoving || this.state.isSlideMoving) {
385 this.leaveTimer = window.setTimeout(this.handleDragEnd, this.props.leaveTimeOut);
386 }
387 });
388 _defineProperty(this, "handleEnterSlideOrTraveller", () => {
389 this.setState({
390 isTextActive: true
391 });
392 });
393 _defineProperty(this, "handleLeaveSlideOrTraveller", () => {
394 this.setState({
395 isTextActive: false
396 });
397 });
398 _defineProperty(this, "handleSlideDragStart", e => {
399 var event = isTouch(e) ? e.changedTouches[0] : e;
400 if (event == null) {
401 return;
402 }
403 this.setState({
404 isTravellerMoving: false,
405 isSlideMoving: true,
406 slideMoveStartX: event.pageX
407 });
408 this.attachDragEndListener();
409 });
410 _defineProperty(this, "handleTravellerMoveKeyboard", (direction, id) => {
411 var {
412 data,
413 gap,
414 startIndex,
415 endIndex
416 } = this.props;
417 // scaleValues are a list of coordinates. For example: [65, 250, 435, 620, 805, 990].
418 var {
419 scaleValues,
420 startX,
421 endX
422 } = this.state;
423 if (scaleValues == null) {
424 return;
425 }
426
427 // unless we search for the closest scaleValue to the current coordinate
428 // we need to move travelers via index when using the keyboard
429 var currentIndex = -1;
430 if (id === 'startX') {
431 currentIndex = startIndex;
432 } else if (id === 'endX') {
433 currentIndex = endIndex;
434 }
435 if (currentIndex < 0 || currentIndex >= data.length) {
436 return;
437 }
438 var newIndex = currentIndex + direction;
439 if (newIndex === -1 || newIndex >= scaleValues.length) {
440 return;
441 }
442 var newScaleValue = scaleValues[newIndex];
443 if (newScaleValue == null) {
444 return;
445 }
446
447 // Prevent travellers from being on top of each other or overlapping
448 if (id === 'startX' && newScaleValue >= endX || id === 'endX' && newScaleValue <= startX) {
449 return;
450 }
451 this.setState(
452 // @ts-expect-error not sure why typescript is not happy with this, partial update is fine in React
453 {
454 [id]: newScaleValue
455 }, () => {
456 this.props.onChange(getIndex({
457 startX: this.state.startX,
458 endX: this.state.endX,
459 data,
460 gap,
461 scaleValues
462 }));
463 });
464 });
465 this.travellerDragStartHandlers = {
466 startX: this.handleTravellerDragStart.bind(this, 'startX'),
467 endX: this.handleTravellerDragStart.bind(this, 'endX')
468 };
469 this.state = {
470 brushMoveStartX: 0,
471 movingTravellerId: undefined,
472 endX: 0,
473 startX: 0,
474 slideMoveStartX: 0
475 };
476 }
477 static getDerivedStateFromProps(nextProps, prevState) {
478 var {
479 data,
480 width,
481 x,
482 travellerWidth,
483 startIndex,
484 endIndex,
485 startIndexControlledFromProps,
486 endIndexControlledFromProps
487 } = nextProps;
488 if (data !== prevState.prevData) {
489 return _objectSpread({
490 prevData: data,
491 prevTravellerWidth: travellerWidth,
492 prevX: x,
493 prevWidth: width
494 }, data && data.length ? createScale({
495 data,
496 width,
497 x,
498 travellerWidth,
499 startIndex,
500 endIndex
501 }) : {
502 scale: undefined,
503 scaleValues: undefined
504 });
505 }
506 var prevScale = prevState.scale;
507 if (prevScale && (width !== prevState.prevWidth || x !== prevState.prevX || travellerWidth !== prevState.prevTravellerWidth)) {
508 prevScale.range([x, x + width - travellerWidth]);
509 var scaleValues = prevScale.domain().map(entry => prevScale(entry)).filter(value => value != null);
510 return {
511 prevData: data,
512 prevTravellerWidth: travellerWidth,
513 prevX: x,
514 prevWidth: width,
515 startX: prevScale(nextProps.startIndex),
516 endX: prevScale(nextProps.endIndex),
517 scaleValues
518 };
519 }
520 if (prevState.scale && !prevState.isSlideMoving && !prevState.isTravellerMoving && !prevState.isTravellerFocused && !prevState.isTextActive) {
521 /*
522 * If the startIndex or endIndex are controlled from the outside,
523 * we need to keep the startX and end up to date.
524 * Also we do not want to do that while user is interacting in the brush,
525 * because this will trigger re-render and interrupt the drag&drop.
526 */
527 if (startIndexControlledFromProps != null && prevState.prevStartIndexControlledFromProps !== startIndexControlledFromProps) {
528 return {
529 startX: prevState.scale(startIndexControlledFromProps),
530 prevStartIndexControlledFromProps: startIndexControlledFromProps
531 };
532 }
533 if (endIndexControlledFromProps != null && prevState.prevEndIndexControlledFromProps !== endIndexControlledFromProps) {
534 return {
535 endX: prevState.scale(endIndexControlledFromProps),
536 prevEndIndexControlledFromProps: endIndexControlledFromProps
537 };
538 }
539 }
540 return null;
541 }
542 componentWillUnmount() {
543 if (this.leaveTimer) {
544 clearTimeout(this.leaveTimer);
545 this.leaveTimer = null;
546 }
547 this.detachDragEndListener();
548 }
549 attachDragEndListener() {
550 window.addEventListener('mouseup', this.handleDragEnd, true);
551 window.addEventListener('touchend', this.handleDragEnd, true);
552 window.addEventListener('mousemove', this.handleDrag, true);
553 }
554 detachDragEndListener() {
555 window.removeEventListener('mouseup', this.handleDragEnd, true);
556 window.removeEventListener('touchend', this.handleDragEnd, true);
557 window.removeEventListener('mousemove', this.handleDrag, true);
558 }
559 handleSlideDrag(e) {
560 var {
561 slideMoveStartX,
562 startX,
563 endX,
564 scaleValues
565 } = this.state;
566 if (scaleValues == null) {
567 return;
568 }
569 var {
570 x,
571 width,
572 travellerWidth,
573 startIndex,
574 endIndex,
575 onChange,
576 data,
577 gap
578 } = this.props;
579 var delta = e.pageX - slideMoveStartX;
580 if (delta > 0) {
581 delta = Math.min(delta, x + width - travellerWidth - endX, x + width - travellerWidth - startX);
582 } else if (delta < 0) {
583 delta = Math.max(delta, x - startX, x - endX);
584 }
585 var newIndex = getIndex({
586 startX: startX + delta,
587 endX: endX + delta,
588 data,
589 gap,
590 scaleValues
591 });
592 if ((newIndex.startIndex !== startIndex || newIndex.endIndex !== endIndex) && onChange) {
593 onChange(newIndex);
594 }
595 this.setState({
596 startX: startX + delta,
597 endX: endX + delta,
598 slideMoveStartX: e.pageX
599 });
600 }
601 handleTravellerDragStart(id, e) {
602 var event = isTouch(e) ? e.changedTouches[0] : e;
603 if (event == null) {
604 return;
605 }
606 this.setState({
607 isSlideMoving: false,
608 isTravellerMoving: true,
609 movingTravellerId: id,
610 brushMoveStartX: event.pageX
611 });
612 this.attachDragEndListener();
613 }
614 handleTravellerMove(e) {
615 var {
616 brushMoveStartX,
617 movingTravellerId,
618 endX,
619 startX,
620 scaleValues
621 } = this.state;
622 if (movingTravellerId == null || scaleValues == null) {
623 return;
624 }
625 var prevValue = this.state[movingTravellerId];
626 var {
627 x,
628 width,
629 travellerWidth,
630 onChange,
631 gap,
632 data
633 } = this.props;
634 var params = {
635 startX: this.state.startX,
636 endX: this.state.endX,
637 data,
638 gap,
639 scaleValues
640 };
641 var delta = e.pageX - brushMoveStartX;
642 if (delta > 0) {
643 delta = Math.min(delta, x + width - travellerWidth - prevValue);
644 } else if (delta < 0) {
645 delta = Math.max(delta, x - prevValue);
646 }
647 params[movingTravellerId] = prevValue + delta;
648 var newIndex = getIndex(params);
649 var {
650 startIndex,
651 endIndex
652 } = newIndex;
653 var isFullGap = () => {
654 var lastIndex = data.length - 1;
655 if (movingTravellerId === 'startX' && (endX > startX ? startIndex % gap === 0 : endIndex % gap === 0) || endX < startX && endIndex === lastIndex || movingTravellerId === 'endX' && (endX > startX ? endIndex % gap === 0 : startIndex % gap === 0) || endX > startX && endIndex === lastIndex) {
656 return true;
657 }
658 return false;
659 };
660 this.setState(
661 // @ts-expect-error not sure why typescript is not happy with this, partial update is fine in React
662 {
663 [movingTravellerId]: prevValue + delta,
664 brushMoveStartX: e.pageX
665 }, () => {
666 if (onChange) {
667 if (isFullGap()) {
668 onChange(newIndex);
669 }
670 }
671 });
672 }
673 render() {
674 var {
675 data,
676 className,
677 children,
678 x,
679 y,
680 dy,
681 width,
682 height,
683 alwaysShowText,
684 fill,
685 stroke,
686 startIndex,
687 endIndex,
688 travellerWidth,
689 tickFormatter,
690 dataKey,
691 padding
692 } = this.props;
693 var {
694 startX,
695 endX,
696 isTextActive,
697 isSlideMoving,
698 isTravellerMoving,
699 isTravellerFocused
700 } = this.state;
701 if (!data || !data.length || !isNumber(x) || !isNumber(y) || !isNumber(width) || !isNumber(height) || width <= 0 || height <= 0) {
702 return null;
703 }
704 var layerClass = clsx('recharts-brush', className);
705 var style = generatePrefixStyle('userSelect', 'none');
706 var calculatedY = y + (dy !== null && dy !== void 0 ? dy : 0);
707 return /*#__PURE__*/React.createElement(Layer, {
708 className: layerClass,
709 onMouseLeave: this.handleLeaveWrapper,
710 onTouchMove: this.handleTouchMove,
711 style: style
712 }, /*#__PURE__*/React.createElement(Background, {
713 x: x,
714 y: calculatedY,
715 width: width,
716 height: height,
717 fill: fill,
718 stroke: stroke
719 }), /*#__PURE__*/React.createElement(PanoramaContextProvider, null, /*#__PURE__*/React.createElement(Panorama, {
720 x: x,
721 y: calculatedY,
722 width: width,
723 height: height,
724 data: data,
725 padding: padding
726 }, children)), /*#__PURE__*/React.createElement(Slide, {
727 y: calculatedY,
728 height: height,
729 stroke: stroke,
730 travellerWidth: travellerWidth,
731 startX: startX,
732 endX: endX,
733 onMouseEnter: this.handleEnterSlideOrTraveller,
734 onMouseLeave: this.handleLeaveSlideOrTraveller,
735 onMouseDown: this.handleSlideDragStart,
736 onTouchStart: this.handleSlideDragStart
737 }), /*#__PURE__*/React.createElement(TravellerLayer, {
738 travellerX: startX,
739 id: "startX",
740 otherProps: _objectSpread(_objectSpread({}, this.props), {}, {
741 y: calculatedY
742 }),
743 onMouseEnter: this.handleEnterSlideOrTraveller,
744 onMouseLeave: this.handleLeaveSlideOrTraveller,
745 onMouseDown: this.travellerDragStartHandlers.startX,
746 onTouchStart: this.travellerDragStartHandlers.startX,
747 onTravellerMoveKeyboard: this.handleTravellerMoveKeyboard,
748 onFocus: () => {
749 this.setState({
750 isTravellerFocused: true
751 });
752 },
753 onBlur: () => {
754 this.setState({
755 isTravellerFocused: false
756 });
757 }
758 }), /*#__PURE__*/React.createElement(TravellerLayer, {
759 travellerX: endX,
760 id: "endX",
761 otherProps: _objectSpread(_objectSpread({}, this.props), {}, {
762 y: calculatedY
763 }),
764 onMouseEnter: this.handleEnterSlideOrTraveller,
765 onMouseLeave: this.handleLeaveSlideOrTraveller,
766 onMouseDown: this.travellerDragStartHandlers.endX,
767 onTouchStart: this.travellerDragStartHandlers.endX,
768 onTravellerMoveKeyboard: this.handleTravellerMoveKeyboard,
769 onFocus: () => {
770 this.setState({
771 isTravellerFocused: true
772 });
773 },
774 onBlur: () => {
775 this.setState({
776 isTravellerFocused: false
777 });
778 }
779 }), (isTextActive || isSlideMoving || isTravellerMoving || isTravellerFocused || alwaysShowText) && /*#__PURE__*/React.createElement(BrushText, {
780 startIndex: startIndex,
781 endIndex: endIndex,
782 y: calculatedY,
783 height: height,
784 travellerWidth: travellerWidth,
785 stroke: stroke,
786 tickFormatter: tickFormatter,
787 dataKey: dataKey,
788 data: data,
789 startX: startX,
790 endX: endX
791 }));
792 }
793}
794function BrushInternal(props) {
795 var dispatch = useAppDispatch();
796 var chartData = useChartData();
797 var dataIndexes = useDataIndex();
798 var onChangeFromContext = useContext(BrushUpdateDispatchContext);
799 var onChangeFromProps = props.onChange;
800 var {
801 startIndex: startIndexFromProps,
802 endIndex: endIndexFromProps
803 } = props;
804 useEffect(() => {
805 // start and end index can be controlled from props, and we need them to stay up-to-date in the Redux state too
806 dispatch(setDataStartEndIndexes({
807 startIndex: startIndexFromProps,
808 endIndex: endIndexFromProps
809 }));
810 }, [dispatch, endIndexFromProps, startIndexFromProps]);
811 useBrushChartSynchronisation();
812 var onChange = useCallback(nextState => {
813 if (dataIndexes == null) {
814 return;
815 }
816 var {
817 startIndex,
818 endIndex
819 } = dataIndexes;
820 if (nextState.startIndex !== startIndex || nextState.endIndex !== endIndex) {
821 onChangeFromContext === null || onChangeFromContext === void 0 || onChangeFromContext(nextState);
822 onChangeFromProps === null || onChangeFromProps === void 0 || onChangeFromProps(nextState);
823 dispatch(setDataStartEndIndexes(nextState));
824 }
825 }, [onChangeFromProps, onChangeFromContext, dispatch, dataIndexes]);
826 var brushDimensions = useAppSelector(selectBrushDimensions);
827 if (brushDimensions == null || dataIndexes == null || chartData == null || !chartData.length) {
828 return null;
829 }
830 var {
831 startIndex,
832 endIndex
833 } = dataIndexes;
834 var {
835 x,
836 y,
837 width
838 } = brushDimensions;
839 var contextProperties = {
840 data: chartData,
841 x,
842 y,
843 width,
844 startIndex,
845 endIndex,
846 onChange
847 };
848 return /*#__PURE__*/React.createElement(BrushWithState, _extends({}, props, contextProperties, {
849 startIndexControlledFromProps: startIndexFromProps !== null && startIndexFromProps !== void 0 ? startIndexFromProps : undefined,
850 endIndexControlledFromProps: endIndexFromProps !== null && endIndexFromProps !== void 0 ? endIndexFromProps : undefined
851 }));
852}
853function BrushSettingsDispatcher(props) {
854 var dispatch = useAppDispatch();
855 useEffect(() => {
856 dispatch(setBrushSettings(props));
857 return () => {
858 dispatch(setBrushSettings(null));
859 };
860 }, [dispatch, props]);
861 return null;
862}
863export var defaultBrushProps = {
864 height: 40,
865 travellerWidth: 5,
866 gap: 1,
867 fill: '#fff',
868 stroke: '#666',
869 padding: {
870 top: 1,
871 right: 1,
872 bottom: 1,
873 left: 1
874 },
875 leaveTimeOut: 1000,
876 alwaysShowText: false
877};
878
879/**
880 * Renders a scrollbar that allows the user to zoom and pan in the chart along its XAxis.
881 * It also allows you to render a small overview of the chart inside the brush that is always visible
882 * and shows the full data set so that the user can see where they are zoomed in.
883 *
884 * If a chart is synchronized with other charts using the `syncId` prop on the chart,
885 * the brush will also synchronize the zooming and panning between all synchronized charts.
886 *
887 * @see {@link https://recharts.github.io/en-US/examples/BrushBarChart/ BarChart with Brush}
888 * @see {@link https://recharts.github.io/en-US/examples/SynchronizedLineChart/ Synchronized Brush}
889 *
890 * @consumes CartesianChartContext
891 */
892export function Brush(outsideProps) {
893 var props = resolveDefaultProps(outsideProps, defaultBrushProps);
894 return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(BrushSettingsDispatcher, {
895 height: props.height,
896 x: props.x,
897 y: props.y,
898 width: props.width,
899 padding: props.padding
900 }), /*#__PURE__*/React.createElement(BrushInternal, props));
901}
902Brush.displayName = 'Brush';
Note: See TracBrowser for help on using the repository browser.