@gravity-ui/date-components 2.10.0 → 2.11.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/RangeDateSelection/RangeDateSelection.css +28 -0
- package/dist/cjs/components/RangeDateSelection/RangeDateSelection.d.ts +24 -0
- package/dist/cjs/components/RangeDateSelection/RangeDateSelection.js +49 -0
- package/dist/cjs/components/RangeDateSelection/components/NowLine/NowLine.css +4 -0
- package/dist/cjs/components/RangeDateSelection/components/NowLine/NowLine.d.ts +2 -0
- package/dist/cjs/components/RangeDateSelection/components/NowLine/NowLine.js +43 -0
- package/dist/cjs/components/RangeDateSelection/components/Ruler/Ruler.d.ts +32 -0
- package/dist/cjs/components/RangeDateSelection/components/Ruler/Ruler.js +61 -0
- package/dist/cjs/components/RangeDateSelection/components/RulerViewport/RulerViewport.css +25 -0
- package/dist/cjs/components/RangeDateSelection/components/RulerViewport/RulerViewport.d.ts +13 -0
- package/dist/cjs/components/RangeDateSelection/components/RulerViewport/RulerViewport.js +35 -0
- package/dist/cjs/components/RangeDateSelection/components/SelectionControl/SelectionControl.css +78 -0
- package/dist/cjs/components/RangeDateSelection/components/SelectionControl/SelectionControl.d.ts +8 -0
- package/dist/cjs/components/RangeDateSelection/components/SelectionControl/SelectionControl.js +135 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/MiddleTicks.d.ts +3 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/MiddleTicks.js +10 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/SlitTicks.d.ts +5 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/SlitTicks.js +10 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/Ticks.css +16 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/Ticks.d.ts +18 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/Ticks.js +52 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/UnavialableTicks.d.ts +15 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/UnavialableTicks.js +50 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/utils.d.ts +24 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/utils.js +166 -0
- package/dist/cjs/components/RangeDateSelection/hooks/useRangeDateSelectionState.d.ts +60 -0
- package/dist/cjs/components/RangeDateSelection/hooks/useRangeDateSelectionState.js +150 -0
- package/dist/cjs/components/RangeDateSelection/i18n/en.json +7 -0
- package/dist/cjs/components/RangeDateSelection/i18n/index.d.ts +1 -0
- package/dist/cjs/components/RangeDateSelection/i18n/index.js +11 -0
- package/dist/cjs/components/RangeDateSelection/i18n/ru.json +7 -0
- package/dist/cjs/components/RangeDateSelection/index.d.ts +3 -0
- package/dist/cjs/components/RangeDateSelection/index.js +18 -0
- package/dist/cjs/components/RangeDateSelection/utils/date.d.ts +2 -0
- package/dist/cjs/components/RangeDateSelection/utils/date.js +10 -0
- package/dist/cjs/components/RangeDateSelection/utils/span.d.ts +23 -0
- package/dist/cjs/components/RangeDateSelection/utils/span.js +27 -0
- package/dist/cjs/components/RelativeRangeDatePicker/components/Presets/i18n/index.d.ts +1 -1
- package/dist/cjs/components/RelativeRangeDatePicker/index.d.ts +1 -0
- package/dist/cjs/components/RelativeRangeDatePicker/index.js +1 -0
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/components/mixins.css +0 -0
- package/dist/cjs/components/utils/constants.d.ts +7 -0
- package/dist/cjs/components/utils/constants.js +10 -0
- package/dist/cjs/components/utils/filterDOMProps.d.ts +17 -0
- package/dist/cjs/components/utils/filterDOMProps.js +27 -0
- package/dist/cjs/hooks/useEventHandler.d.ts +1 -0
- package/dist/cjs/hooks/useEventHandler.js +24 -0
- package/dist/cjs/hooks/useMove.d.ts +31 -0
- package/dist/cjs/hooks/useMove.js +173 -0
- package/dist/cjs/hooks/useResizeObserver.d.ts +8 -0
- package/dist/cjs/hooks/useResizeObserver.js +32 -0
- package/dist/esm/components/RangeDateSelection/RangeDateSelection.css +28 -0
- package/dist/esm/components/RangeDateSelection/RangeDateSelection.d.ts +24 -0
- package/dist/esm/components/RangeDateSelection/RangeDateSelection.js +43 -0
- package/dist/esm/components/RangeDateSelection/components/NowLine/NowLine.css +4 -0
- package/dist/esm/components/RangeDateSelection/components/NowLine/NowLine.d.ts +2 -0
- package/dist/esm/components/RangeDateSelection/components/NowLine/NowLine.js +37 -0
- package/dist/esm/components/RangeDateSelection/components/Ruler/Ruler.d.ts +32 -0
- package/dist/esm/components/RangeDateSelection/components/Ruler/Ruler.js +53 -0
- package/dist/esm/components/RangeDateSelection/components/RulerViewport/RulerViewport.css +25 -0
- package/dist/esm/components/RangeDateSelection/components/RulerViewport/RulerViewport.d.ts +13 -0
- package/dist/esm/components/RangeDateSelection/components/RulerViewport/RulerViewport.js +29 -0
- package/dist/esm/components/RangeDateSelection/components/SelectionControl/SelectionControl.css +78 -0
- package/dist/esm/components/RangeDateSelection/components/SelectionControl/SelectionControl.d.ts +8 -0
- package/dist/esm/components/RangeDateSelection/components/SelectionControl/SelectionControl.js +132 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/MiddleTicks.d.ts +3 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/MiddleTicks.js +7 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/SlitTicks.d.ts +5 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/SlitTicks.js +7 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/Ticks.css +16 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/Ticks.d.ts +18 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/Ticks.js +44 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/UnavialableTicks.d.ts +15 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/UnavialableTicks.js +42 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/utils.d.ts +24 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/utils.js +158 -0
- package/dist/esm/components/RangeDateSelection/hooks/useRangeDateSelectionState.d.ts +60 -0
- package/dist/esm/components/RangeDateSelection/hooks/useRangeDateSelectionState.js +144 -0
- package/dist/esm/components/RangeDateSelection/i18n/en.json +7 -0
- package/dist/esm/components/RangeDateSelection/i18n/index.d.ts +1 -0
- package/dist/esm/components/RangeDateSelection/i18n/index.js +5 -0
- package/dist/esm/components/RangeDateSelection/i18n/ru.json +7 -0
- package/dist/esm/components/RangeDateSelection/index.d.ts +3 -0
- package/dist/esm/components/RangeDateSelection/index.js +2 -0
- package/dist/esm/components/RangeDateSelection/utils/date.d.ts +2 -0
- package/dist/esm/components/RangeDateSelection/utils/date.js +7 -0
- package/dist/esm/components/RangeDateSelection/utils/span.d.ts +23 -0
- package/dist/esm/components/RangeDateSelection/utils/span.js +23 -0
- package/dist/esm/components/RelativeRangeDatePicker/components/Presets/i18n/index.d.ts +1 -1
- package/dist/esm/components/RelativeRangeDatePicker/index.d.ts +1 -0
- package/dist/esm/components/RelativeRangeDatePicker/index.js +1 -0
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/mixins.css +0 -0
- package/dist/esm/components/utils/constants.d.ts +7 -0
- package/dist/esm/components/utils/constants.js +7 -0
- package/dist/esm/components/utils/filterDOMProps.d.ts +17 -0
- package/dist/esm/components/utils/filterDOMProps.js +24 -0
- package/dist/esm/hooks/useEventHandler.d.ts +1 -0
- package/dist/esm/hooks/useEventHandler.js +18 -0
- package/dist/esm/hooks/useMove.d.ts +31 -0
- package/dist/esm/hooks/useMove.js +167 -0
- package/dist/esm/hooks/useResizeObserver.d.ts +8 -0
- package/dist/esm/hooks/useResizeObserver.js +26 -0
- package/package.json +1 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useMove } from '../../../../hooks/useMove';
|
|
5
|
+
import { block } from '../../../../utils/cn';
|
|
6
|
+
import './RulerViewport.css';
|
|
7
|
+
const b = block('ruler-viewport');
|
|
8
|
+
function RulerViewport({ className, children, onMove, onMoveStart, onMoveEnd, dragDisabled }, ref) {
|
|
9
|
+
const containerRef = React.useRef(null);
|
|
10
|
+
const draggable = typeof onMove === 'function';
|
|
11
|
+
const { moveProps } = useMove({
|
|
12
|
+
onMoveStart: onMoveStart,
|
|
13
|
+
onMove: (e) => {
|
|
14
|
+
const container = containerRef.current;
|
|
15
|
+
if (e.deltaX !== 0 && container) {
|
|
16
|
+
const { width } = container.getBoundingClientRect();
|
|
17
|
+
let delta = (e.deltaX * 100) / width;
|
|
18
|
+
delta = Math.round(delta * 100) / 100;
|
|
19
|
+
if (delta !== 0) {
|
|
20
|
+
onMove === null || onMove === void 0 ? void 0 : onMove(delta, e);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
onMoveEnd: onMoveEnd,
|
|
25
|
+
});
|
|
26
|
+
return (_jsxs("div", { ref: ref, className: b(null, className), children: [_jsxs("svg", { ref: containerRef, className: b('svg'), width: "100%", height: "100%", xmlns: "http://www.w3.org/2000/svg", xmlnsXlink: "http://www.w3.org/1999/xlink", children: [_jsx("defs", { children: _jsxs("filter", { x: "0", y: "0", width: "1", height: "1", id: "g-date-tt-ticklabelbg", children: [_jsx("feFlood", { floodColor: "var(--_--g-date-ruler-viewport-background)" }), _jsx("feComposite", { in: "SourceGraphic" })] }) }), children] }), draggable ? (_jsx("div", Object.assign({ className: b('dragger', { disabled: dragDisabled }) }, moveProps))) : null] }));
|
|
27
|
+
}
|
|
28
|
+
const _RulerViewport = React.forwardRef(RulerViewport);
|
|
29
|
+
export { _RulerViewport as RulerViewport };
|
package/dist/esm/components/RangeDateSelection/components/SelectionControl/SelectionControl.css
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
.g-date-range-date-selection-control {
|
|
2
|
+
--_--g-date-timeline-color-selection: var(
|
|
3
|
+
--g-date-timeline-color-selection,
|
|
4
|
+
var(--g-color-base-info-light)
|
|
5
|
+
);
|
|
6
|
+
--_--g-date-timeline-color-selection-hover: var(
|
|
7
|
+
--g-date-timeline-color-selection-hover,
|
|
8
|
+
var(--g-color-base-info-light-hover)
|
|
9
|
+
);
|
|
10
|
+
--_--g-date-timeline-color-selection-handle: var(
|
|
11
|
+
--g-date-timeline-color-selection-handle,
|
|
12
|
+
var(--g-color-base-brand)
|
|
13
|
+
);
|
|
14
|
+
--_--g-date-timeline-color-selection-handle-hover: var(
|
|
15
|
+
--g-date-timeline-color-selection-handle-hover,
|
|
16
|
+
var(--g-color-base-brand-hover)
|
|
17
|
+
);
|
|
18
|
+
position: absolute;
|
|
19
|
+
z-index: 1;
|
|
20
|
+
inset-block: 0;
|
|
21
|
+
}
|
|
22
|
+
@supports (selector(:has(*))) and (selector(:focus-visible)) {
|
|
23
|
+
.g-date-range-date-selection-control__start:has(.g-date-range-date-selection-control__slider-input:focus-visible), .g-date-range-date-selection-control__end:has(.g-date-range-date-selection-control__slider-input:focus-visible), .g-date-range-date-selection-control__dragger:has(.g-date-range-date-selection-control__slider-input:focus-visible) {
|
|
24
|
+
border-radius: var(--g-border-radius-xs);
|
|
25
|
+
outline: var(--g-color-line-focus) solid 2px;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
@supports not (selector(:has(*))) {
|
|
29
|
+
.g-date-range-date-selection-control__start:focus-within, .g-date-range-date-selection-control__end:focus-within, .g-date-range-date-selection-control__dragger:focus-within {
|
|
30
|
+
border-radius: var(--g-border-radius-xs);
|
|
31
|
+
outline: var(--g-color-line-focus) solid 2px;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
.g-date-range-date-selection-control__dragger {
|
|
35
|
+
position: absolute;
|
|
36
|
+
inset-block: 0;
|
|
37
|
+
inset-inline: 2px;
|
|
38
|
+
cursor: move;
|
|
39
|
+
background: var(--_--g-date-timeline-color-selection);
|
|
40
|
+
}
|
|
41
|
+
.g-date-range-date-selection-control__dragger:hover, .g-date-range-date-selection-control__dragger_dragging {
|
|
42
|
+
background: var(--_--g-date-timeline-color-selection-hover);
|
|
43
|
+
}
|
|
44
|
+
.g-date-range-date-selection-control__dragger_disabled {
|
|
45
|
+
pointer-events: none;
|
|
46
|
+
}
|
|
47
|
+
.g-date-range-date-selection-control__start {
|
|
48
|
+
position: absolute;
|
|
49
|
+
inset-block: 0;
|
|
50
|
+
inset-inline-start: 0;
|
|
51
|
+
width: 4px;
|
|
52
|
+
background: var(--_--g-date-timeline-color-selection-handle);
|
|
53
|
+
}
|
|
54
|
+
.g-date-range-date-selection-control__end {
|
|
55
|
+
position: absolute;
|
|
56
|
+
inset-inline-end: 0;
|
|
57
|
+
width: 4px;
|
|
58
|
+
height: 100%;
|
|
59
|
+
background: var(--_--g-date-timeline-color-selection-handle);
|
|
60
|
+
}
|
|
61
|
+
.g-date-range-date-selection-control__start, .g-date-range-date-selection-control__end {
|
|
62
|
+
cursor: ew-resize;
|
|
63
|
+
}
|
|
64
|
+
.g-date-range-date-selection-control__start:hover, .g-date-range-date-selection-control__start_dragging, .g-date-range-date-selection-control__end:hover, .g-date-range-date-selection-control__end_dragging {
|
|
65
|
+
background: var(--_--g-date-timeline-color-selection-handle-hover);
|
|
66
|
+
}
|
|
67
|
+
.g-date-range-date-selection-control__slider-input-wrapper {
|
|
68
|
+
position: absolute;
|
|
69
|
+
overflow: hidden;
|
|
70
|
+
clip: rect(0, 0, 0, 0);
|
|
71
|
+
width: 1px;
|
|
72
|
+
height: 1px;
|
|
73
|
+
margin: -1px;
|
|
74
|
+
padding: 0;
|
|
75
|
+
white-space: nowrap;
|
|
76
|
+
border: 0;
|
|
77
|
+
clip-path: inset(50%);
|
|
78
|
+
}
|
package/dist/esm/components/RangeDateSelection/components/SelectionControl/SelectionControl.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AccessibilityProps, DomProps, StyleProps } from '../../../types';
|
|
2
|
+
import type { RangeDateSelectionState } from '../../hooks/useRangeDateSelectionState';
|
|
3
|
+
import './SelectionControl.css';
|
|
4
|
+
interface SelectionControlProps extends DomProps, StyleProps, AccessibilityProps {
|
|
5
|
+
state: RangeDateSelectionState;
|
|
6
|
+
}
|
|
7
|
+
export declare function SelectionControl({ state, style, className, ...props }: SelectionControlProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
package/dist/esm/components/RangeDateSelection/components/SelectionControl/SelectionControl.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useMove } from '../../../../hooks/useMove';
|
|
5
|
+
import { block } from '../../../../utils/cn';
|
|
6
|
+
import { i18n } from '../../i18n';
|
|
7
|
+
import { lerp } from '../../utils/span';
|
|
8
|
+
import { useViewportDimensions, useViewportInterval } from '../Ruler/Ruler';
|
|
9
|
+
import './SelectionControl.css';
|
|
10
|
+
const b = block('range-date-selection-control');
|
|
11
|
+
const MIN_SELECTION_WIDTH = 12; // px;
|
|
12
|
+
const MIN_DRAG_SCALE = 0.01;
|
|
13
|
+
const MAX_DRAG_SCALE = 100;
|
|
14
|
+
const DRAG_SCALE_STRENGTH = 20;
|
|
15
|
+
export function SelectionControl(_a) {
|
|
16
|
+
var _b;
|
|
17
|
+
var { state, style, className } = _a, props = __rest(_a, ["state", "style", "className"]);
|
|
18
|
+
const { start: startDate, end: endDate } = useViewportInterval();
|
|
19
|
+
const viewport = useViewportDimensions();
|
|
20
|
+
const [isDragging, setIsDragging] = React.useState(null);
|
|
21
|
+
const moveDataRef = React.useRef({
|
|
22
|
+
isZooming: false,
|
|
23
|
+
});
|
|
24
|
+
const visualMinDuration = (MIN_SELECTION_WIDTH * (endDate.valueOf() - startDate.valueOf())) / viewport.width;
|
|
25
|
+
const handleMoveEnd = () => {
|
|
26
|
+
state.endDragging();
|
|
27
|
+
setIsDragging(null);
|
|
28
|
+
};
|
|
29
|
+
const { moveProps } = useMove({
|
|
30
|
+
onMoveStart: (e) => {
|
|
31
|
+
setIsDragging('dragger');
|
|
32
|
+
state.startDragging();
|
|
33
|
+
moveDataRef.current = {
|
|
34
|
+
isZooming: state.canResize && (e.ctrlKey || e.metaKey),
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
onMoveEnd: handleMoveEnd,
|
|
38
|
+
onMove: (e) => {
|
|
39
|
+
if (e.deltaX === 0) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (moveDataRef.current.isZooming) {
|
|
43
|
+
let scale = Math.exp((e.deltaX * DRAG_SCALE_STRENGTH) / viewport.width);
|
|
44
|
+
scale = Math.min(Math.max(scale, MIN_DRAG_SCALE), MAX_DRAG_SCALE);
|
|
45
|
+
state.scale(scale, { visualMinDuration });
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
let delta = (e.deltaX * (endDate.valueOf() - startDate.valueOf())) / viewport.width;
|
|
49
|
+
if (e.pointerType === 'keyboard') {
|
|
50
|
+
delta =
|
|
51
|
+
delta > 0
|
|
52
|
+
? Math.max(delta, state.align)
|
|
53
|
+
: Math.min(delta, -1 * state.align);
|
|
54
|
+
}
|
|
55
|
+
state.move(delta, { visualMinDuration });
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
const { moveProps: moveStartProps } = useMove({
|
|
60
|
+
onMoveStart: () => {
|
|
61
|
+
setIsDragging('start');
|
|
62
|
+
state.startDragging();
|
|
63
|
+
},
|
|
64
|
+
onMoveEnd: handleMoveEnd,
|
|
65
|
+
onMove: (e) => {
|
|
66
|
+
if (e.deltaX === 0) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
let delta = (e.deltaX * (endDate.valueOf() - startDate.valueOf())) / viewport.width;
|
|
70
|
+
if (e.pointerType === 'keyboard') {
|
|
71
|
+
delta =
|
|
72
|
+
delta > 0 ? Math.max(delta, state.align) : Math.min(delta, -1 * state.align);
|
|
73
|
+
}
|
|
74
|
+
state.moveStart(delta, { visualMinDuration });
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
const { moveProps: moveEndProps } = useMove({
|
|
78
|
+
onMoveStart: () => {
|
|
79
|
+
setIsDragging('end');
|
|
80
|
+
state.startDragging();
|
|
81
|
+
},
|
|
82
|
+
onMoveEnd: handleMoveEnd,
|
|
83
|
+
onMove: (e) => {
|
|
84
|
+
if (e.deltaX === 0) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
let delta = (e.deltaX * (endDate.valueOf() - startDate.valueOf())) / viewport.width;
|
|
88
|
+
if (e.pointerType === 'keyboard') {
|
|
89
|
+
delta =
|
|
90
|
+
delta > 0 ? Math.max(delta, state.align) : Math.min(delta, -1 * state.align);
|
|
91
|
+
}
|
|
92
|
+
state.moveEnd(delta, { visualMinDuration });
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
const { start: startValue, end: endValue } = state.value;
|
|
96
|
+
const startX = lerp({ start: startDate.valueOf(), end: endDate.valueOf() }, { start: 0, end: viewport.width }, startValue.valueOf());
|
|
97
|
+
const endX = lerp({ start: startDate.valueOf(), end: endDate.valueOf() }, { start: 0, end: viewport.width }, endValue.valueOf());
|
|
98
|
+
const draggerInputRef = React.useRef(null);
|
|
99
|
+
const startInputRef = React.useRef(null);
|
|
100
|
+
const endInputRef = React.useRef(null);
|
|
101
|
+
let id = React.useId();
|
|
102
|
+
id = (_b = props.id) !== null && _b !== void 0 ? _b : id;
|
|
103
|
+
return (_jsxs("div", { className: b(null, className), style: Object.assign(Object.assign({}, style), { left: startX, width: endX - startX }), children: [_jsx("div", Object.assign({ className: b('dragger', {
|
|
104
|
+
dragging: isDragging === 'dragger',
|
|
105
|
+
disabled: Boolean(isDragging && isDragging !== 'dragger'),
|
|
106
|
+
}) }, moveProps, { onClick: () => {
|
|
107
|
+
var _a;
|
|
108
|
+
(_a = draggerInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
109
|
+
}, children: _jsx("div", { className: b('slider-input-wrapper'), children: _jsx("input", { id: `${id}-range`, ref: draggerInputRef, className: b('slider-input'), type: "range", step: 1, "aria-label": i18n('Range'), "aria-labelledby": [`${id}-range`, props['aria-labelledby']]
|
|
110
|
+
.filter(Boolean)
|
|
111
|
+
.join(' '), "aria-orientation": "horizontal", "aria-valuetext": `${startValue.format()} - ${endValue.format()}`, value: 0, onChange: () => { } }) }) })), state.canResize ? (
|
|
112
|
+
/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
|
|
113
|
+
_jsx("div", Object.assign({ className: b('start', {
|
|
114
|
+
dragging: isDragging === 'start',
|
|
115
|
+
disabled: Boolean(isDragging && isDragging !== 'start'),
|
|
116
|
+
}) }, moveStartProps, { onClick: () => {
|
|
117
|
+
var _a;
|
|
118
|
+
(_a = startInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
119
|
+
}, children: _jsx("div", { className: b('slider-input-wrapper'), children: _jsx("input", { id: `${id}-start`, ref: startInputRef, className: b('slider-input'), type: "range", step: 1, "aria-label": i18n('Start of range'), "aria-labelledby": [`${id}-start`, props['aria-labelledby']]
|
|
120
|
+
.filter(Boolean)
|
|
121
|
+
.join(' '), "aria-orientation": "horizontal", "aria-valuetext": `${startValue.format()}`, value: 0, onChange: () => { } }) }) }))) : null, state.canResize ? (
|
|
122
|
+
/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
|
|
123
|
+
_jsx("div", Object.assign({ className: b('end', {
|
|
124
|
+
dragging: isDragging === 'end',
|
|
125
|
+
disabled: Boolean(isDragging && isDragging !== 'end'),
|
|
126
|
+
}) }, moveEndProps, { onClick: () => {
|
|
127
|
+
var _a;
|
|
128
|
+
(_a = endInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
129
|
+
}, children: _jsx("div", { className: b('slider-input-wrapper'), children: _jsx("input", { id: `${id}-end`, ref: endInputRef, className: b('slider-input'), type: "range", step: 1, "aria-label": i18n('End of range'), "aria-labelledby": [`${id}-end`, props['aria-labelledby']]
|
|
130
|
+
.filter(Boolean)
|
|
131
|
+
.join(' '), "aria-orientation": "horizontal", "aria-valuetext": `${endValue.format()}`, value: 0, onChange: () => { } }) }) }))) : null] }));
|
|
132
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useViewportDimensions } from '../Ruler/Ruler';
|
|
3
|
+
import { Ticks, makeMiddleTicksGeometry } from './Ticks';
|
|
4
|
+
export function MiddleTicks({ timeZone }) {
|
|
5
|
+
const { height } = useViewportDimensions();
|
|
6
|
+
return (_jsx(Ticks, { minTickWidth: 8, maxTickWidth: 20, theme: "dim", geometry: makeMiddleTicksGeometry({ tickHeight: 4, viewportHeight: height }), timeZone: timeZone }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useViewportDimensions } from '../Ruler/Ruler';
|
|
3
|
+
import { Ticks, makeSlitTicksGeometry } from './Ticks';
|
|
4
|
+
export function SlitTicks({ formatTime, timeZone, }) {
|
|
5
|
+
const { height } = useViewportDimensions();
|
|
6
|
+
return (_jsx(Ticks, { minTickWidth: 80, maxTickWidth: 200, theme: "normal", geometry: makeSlitTicksGeometry({ tickHeight: 4, viewportHeight: height }), hasLabels: true, formatTime: formatTime, timeZone: timeZone }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
.g-date-timeline-ticks {
|
|
2
|
+
stroke: var(--g-color-text-secondary);
|
|
3
|
+
fill: var(--g-color-text-secondary);
|
|
4
|
+
stroke-width: 1px;
|
|
5
|
+
}
|
|
6
|
+
.g-date-timeline-ticks_theme_dim {
|
|
7
|
+
stroke: var(--g-color-line-generic-accent);
|
|
8
|
+
fill: var(--g-color-line-generic-accent);
|
|
9
|
+
}
|
|
10
|
+
.g-date-timeline-ticks__label {
|
|
11
|
+
font-size: 11px;
|
|
12
|
+
line-height: 14px;
|
|
13
|
+
user-select: none;
|
|
14
|
+
fill: var(--g-color-text-secondary);
|
|
15
|
+
text-anchor: middle;
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
|
+
import type { Geometry } from './utils';
|
|
3
|
+
import { makeMiddleTicksGeometry, makeSlitTicksGeometry } from './utils';
|
|
4
|
+
import './Ticks.css';
|
|
5
|
+
interface TicksProps {
|
|
6
|
+
theme: 'normal' | 'dim';
|
|
7
|
+
minTickWidth: number;
|
|
8
|
+
maxTickWidth: number;
|
|
9
|
+
hasLabels?: boolean;
|
|
10
|
+
geometry: Geometry;
|
|
11
|
+
className?: string;
|
|
12
|
+
labelsClassName?: string;
|
|
13
|
+
formatTime?: (time: DateTime) => string;
|
|
14
|
+
timeZone?: string;
|
|
15
|
+
}
|
|
16
|
+
export { makeMiddleTicksGeometry, makeSlitTicksGeometry };
|
|
17
|
+
export type { Geometry };
|
|
18
|
+
export declare function Ticks({ theme, minTickWidth, maxTickWidth, hasLabels, geometry, className, labelsClassName, formatTime, timeZone, }: TicksProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { dateTime } from '@gravity-ui/date-utils';
|
|
4
|
+
import { block } from '../../../../utils/cn';
|
|
5
|
+
import { getLerpCoeff } from '../../utils/span';
|
|
6
|
+
import { useViewportDimensions, useViewportInterval } from '../Ruler/Ruler';
|
|
7
|
+
import { calculateTickTimes, formatTick as defaultFormatTime, makeMiddleTicksGeometry, makeSlitTicksGeometry, } from './utils';
|
|
8
|
+
import './Ticks.css';
|
|
9
|
+
const b = block('timeline-ticks');
|
|
10
|
+
export { makeMiddleTicksGeometry, makeSlitTicksGeometry };
|
|
11
|
+
export function Ticks({ theme, minTickWidth, maxTickWidth, hasLabels, geometry, className, labelsClassName, formatTime, timeZone, }) {
|
|
12
|
+
const viewport = useViewportDimensions();
|
|
13
|
+
const interval = useViewportInterval();
|
|
14
|
+
const tickTimes = React.useMemo(() => calculateTickTimes({
|
|
15
|
+
minTickWidth,
|
|
16
|
+
maxTickWidth,
|
|
17
|
+
viewportStart: interval.start,
|
|
18
|
+
viewportEnd: interval.end,
|
|
19
|
+
viewportWidth: viewport.width,
|
|
20
|
+
timeZone,
|
|
21
|
+
}), [maxTickWidth, minTickWidth, interval, viewport.width, timeZone]);
|
|
22
|
+
const tickCoords = React.useMemo(() => {
|
|
23
|
+
const timeToXCoeff = getLerpCoeff({ start: interval.start.valueOf(), end: interval.end.valueOf() }, { start: 0, end: viewport.width });
|
|
24
|
+
return tickTimes.map((t) => 0 + Math.round((t.valueOf() - interval.start.valueOf()) * timeToXCoeff));
|
|
25
|
+
}, [tickTimes, interval, viewport.width]);
|
|
26
|
+
const ticksGeometry = React.useMemo(() => {
|
|
27
|
+
return tickCoords.map(geometry).join('');
|
|
28
|
+
}, [geometry, tickCoords]);
|
|
29
|
+
const ticksPath = _jsx("path", { className: b({ theme }, className), d: ticksGeometry });
|
|
30
|
+
const tickLabels = React.useMemo(() => {
|
|
31
|
+
if (!hasLabels || tickCoords.length < 2) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const result = [];
|
|
35
|
+
for (let i = 0; i < tickCoords.length; i++) {
|
|
36
|
+
const x = tickCoords[i];
|
|
37
|
+
const t = tickTimes[i];
|
|
38
|
+
const dt = dateTime({ input: t, timeZone });
|
|
39
|
+
result.push(_jsx("text", { className: b('label', labelsClassName), dominantBaseline: "middle", x: x, y: "50%", filter: "url(#g-date-tt-ticklabelbg)", children: formatTime ? formatTime(dt) : defaultFormatTime(dt) }, i));
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}, [hasLabels, tickCoords, tickTimes, timeZone, labelsClassName, formatTime]);
|
|
43
|
+
return (_jsxs(React.Fragment, { children: [ticksPath, tickLabels] }));
|
|
44
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
|
+
import type { Geometry } from './utils';
|
|
3
|
+
import { makeMiddleTicksGeometry, makeSlitTicksGeometry } from './utils';
|
|
4
|
+
import './Ticks.css';
|
|
5
|
+
interface TicksProps {
|
|
6
|
+
theme: 'normal' | 'dim';
|
|
7
|
+
tickWidth: number;
|
|
8
|
+
minValue?: DateTime;
|
|
9
|
+
maxValue?: DateTime;
|
|
10
|
+
geometry: Geometry;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
export { makeMiddleTicksGeometry, makeSlitTicksGeometry };
|
|
14
|
+
export type { Geometry };
|
|
15
|
+
export declare function UnavailableTicks({ theme, geometry, tickWidth, minValue, maxValue, className, }: TicksProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { block } from '../../../../utils/cn';
|
|
4
|
+
import { useViewportDimensions, useViewportInterval } from '../Ruler/Ruler';
|
|
5
|
+
import { calculatePosition, makeMiddleTicksGeometry, makeSlitTicksGeometry } from './utils';
|
|
6
|
+
import './Ticks.css';
|
|
7
|
+
const b = block('timeline-ticks');
|
|
8
|
+
export { makeMiddleTicksGeometry, makeSlitTicksGeometry };
|
|
9
|
+
export function UnavailableTicks({ theme, geometry, tickWidth, minValue, maxValue, className, }) {
|
|
10
|
+
const viewport = useViewportDimensions();
|
|
11
|
+
const interval = useViewportInterval();
|
|
12
|
+
const endPoint = calculatePosition(minValue, interval, viewport.width);
|
|
13
|
+
const startPoint = calculatePosition(maxValue, interval, viewport.width);
|
|
14
|
+
const tickCoords = [];
|
|
15
|
+
if (!isNaN(endPoint) && endPoint > 0) {
|
|
16
|
+
let x = endPoint - tickWidth;
|
|
17
|
+
if (endPoint > viewport.width) {
|
|
18
|
+
x = endPoint - tickWidth * Math.floor((endPoint - viewport.width) / tickWidth);
|
|
19
|
+
}
|
|
20
|
+
tickCoords.push(x);
|
|
21
|
+
while (x > 0) {
|
|
22
|
+
x -= tickWidth;
|
|
23
|
+
tickCoords.push(x);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (!isNaN(startPoint) && startPoint < viewport.width) {
|
|
27
|
+
let x = startPoint;
|
|
28
|
+
if (startPoint < 0) {
|
|
29
|
+
x = startPoint + tickWidth * Math.floor((0 - startPoint) / tickWidth) - tickWidth;
|
|
30
|
+
}
|
|
31
|
+
tickCoords.push(x);
|
|
32
|
+
while (x < viewport.width) {
|
|
33
|
+
x += tickWidth;
|
|
34
|
+
tickCoords.push(x);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const ticksGeometry = React.useMemo(() => {
|
|
38
|
+
return tickCoords.map(geometry).join('');
|
|
39
|
+
}, [geometry, tickCoords]);
|
|
40
|
+
const ticksPath = _jsx("path", { className: b({ theme }, className), d: ticksGeometry });
|
|
41
|
+
return _jsx(React.Fragment, { children: ticksPath });
|
|
42
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DateTime } from '@gravity-ui/date-utils/build/typings';
|
|
2
|
+
import type { RangeValue } from '../../../types';
|
|
3
|
+
interface CalculateTicksOptions {
|
|
4
|
+
viewportStart: DateTime;
|
|
5
|
+
viewportEnd: DateTime;
|
|
6
|
+
minTickWidth: number;
|
|
7
|
+
maxTickWidth: number;
|
|
8
|
+
viewportWidth: number;
|
|
9
|
+
timeZone?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function calculateTickTimes({ viewportStart, viewportEnd, minTickWidth, maxTickWidth, viewportWidth, timeZone, }: CalculateTicksOptions): number[];
|
|
12
|
+
export declare function formatTick(t: DateTime): string;
|
|
13
|
+
export interface Geometry {
|
|
14
|
+
(x: number): string;
|
|
15
|
+
}
|
|
16
|
+
interface MakeTicksOptions {
|
|
17
|
+
tickHeight: number;
|
|
18
|
+
viewportHeight: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function makeMiddleTicksGeometry({ tickHeight, viewportHeight }: MakeTicksOptions): Geometry;
|
|
21
|
+
export declare function makeSlitTicksGeometry({ tickHeight, viewportHeight }: MakeTicksOptions): Geometry;
|
|
22
|
+
export declare function makeUnavailableTicksGeometry({ tickHeight, viewportHeight, }: MakeTicksOptions): Geometry;
|
|
23
|
+
export declare function calculatePosition(value: DateTime | undefined, interval: RangeValue<DateTime>, width: number): number;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { dateTimeUtc, settings } from '@gravity-ui/date-utils';
|
|
2
|
+
import { DAY, HOUR, MINUTE, MONTH, SECOND, WEEK, YEAR } from '../../../utils/constants';
|
|
3
|
+
import { getLerpCoeff } from '../../utils/span';
|
|
4
|
+
const MAX_TICKS = 100000;
|
|
5
|
+
function makeTickSizes(periodSize, periodName, ...multipliers) {
|
|
6
|
+
return multipliers.map((m) => ({
|
|
7
|
+
duration: m * periodSize,
|
|
8
|
+
period: periodName,
|
|
9
|
+
multiplier: m,
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
const tickSizes = [
|
|
13
|
+
...makeTickSizes(SECOND, 'second', 1, 2, 5, 10, 15, 30),
|
|
14
|
+
...makeTickSizes(MINUTE, 'minute', 1, 2, 5, 10, 20, 30),
|
|
15
|
+
...makeTickSizes(HOUR, 'hour', 1, 2, 3, 6, 12),
|
|
16
|
+
...makeTickSizes(DAY, 'day', 1, 2, 3),
|
|
17
|
+
...makeTickSizes(WEEK, 'week', 1, 2),
|
|
18
|
+
...makeTickSizes(MONTH, 'month', 1, 2, 3, 6),
|
|
19
|
+
...makeTickSizes(YEAR, 'year', 1, 2, 5, 10, 15, 20, 30),
|
|
20
|
+
];
|
|
21
|
+
const TickFormat = {
|
|
22
|
+
SECONDS: 'HH:mm:ss',
|
|
23
|
+
MINUTES: 'HH:mm',
|
|
24
|
+
DATE: 'DD.MM.YY',
|
|
25
|
+
MONTH: 'MM-YYYY',
|
|
26
|
+
YEAR: 'YYYY',
|
|
27
|
+
};
|
|
28
|
+
function findTickSize({ minWidth, maxWidth, timelineWidth, timelineDuration }) {
|
|
29
|
+
const minDuration = (minWidth / timelineWidth) * timelineDuration;
|
|
30
|
+
const maxDuration = (maxWidth / timelineWidth) * timelineDuration;
|
|
31
|
+
const suitableSizes = [];
|
|
32
|
+
for (const size of tickSizes) {
|
|
33
|
+
if (minDuration <= size.duration) {
|
|
34
|
+
if (size.duration <= maxDuration) {
|
|
35
|
+
suitableSizes.push(size);
|
|
36
|
+
}
|
|
37
|
+
else if (!suitableSizes.length) {
|
|
38
|
+
return size;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!suitableSizes.length) {
|
|
43
|
+
return tickSizes[tickSizes.length - 1];
|
|
44
|
+
}
|
|
45
|
+
return suitableSizes[Math.floor(suitableSizes.length / 2)];
|
|
46
|
+
}
|
|
47
|
+
export function calculateTickTimes({ viewportStart, viewportEnd, minTickWidth, maxTickWidth, viewportWidth, timeZone, }) {
|
|
48
|
+
const tickSize = findTickSize({
|
|
49
|
+
minWidth: minTickWidth,
|
|
50
|
+
maxWidth: maxTickWidth,
|
|
51
|
+
timelineDuration: viewportEnd.valueOf() - viewportStart.valueOf(),
|
|
52
|
+
timelineWidth: viewportWidth,
|
|
53
|
+
});
|
|
54
|
+
let cursor;
|
|
55
|
+
const stableDate = dateTimeUtc({ input: '1977-01-01' }).timeZone(timeZone || settings.getDefaultTimeZone(), true);
|
|
56
|
+
const diff = stableDate.diff(viewportStart, tickSize.period);
|
|
57
|
+
const divider = tickSize.multiplier;
|
|
58
|
+
const multiplier = Math.floor(diff / divider);
|
|
59
|
+
cursor = stableDate.subtract(multiplier * divider, tickSize.period);
|
|
60
|
+
if (viewportStart.isBefore(cursor)) {
|
|
61
|
+
cursor = cursor.subtract(divider, tickSize.period);
|
|
62
|
+
}
|
|
63
|
+
const timeDiff = stableDate.utcOffset() - cursor.utcOffset();
|
|
64
|
+
if (timeDiff !== 0 &&
|
|
65
|
+
(tickSize.period === 'hour' || tickSize.period === 'minute' || tickSize.period === 'second')) {
|
|
66
|
+
cursor = cursor.add(timeDiff, 'minutes');
|
|
67
|
+
}
|
|
68
|
+
const ticks = [];
|
|
69
|
+
let i = 0;
|
|
70
|
+
let maxTickValue = cursor.valueOf();
|
|
71
|
+
while (cursor.valueOf() < viewportEnd.valueOf()) {
|
|
72
|
+
if (i >= MAX_TICKS) {
|
|
73
|
+
throw new Error('TimeLine: too much ticks');
|
|
74
|
+
}
|
|
75
|
+
i++;
|
|
76
|
+
ticks.push(cursor.valueOf());
|
|
77
|
+
let next = cursor.add(tickSize.multiplier, tickSize.period);
|
|
78
|
+
// Get time shift when season timeZone changed
|
|
79
|
+
const timeDiff = cursor.utcOffset() - next.utcOffset();
|
|
80
|
+
if (timeDiff !== 0 &&
|
|
81
|
+
(tickSize.period === 'hour' ||
|
|
82
|
+
tickSize.period === 'minute' ||
|
|
83
|
+
tickSize.period === 'second')) {
|
|
84
|
+
// Tick should be on same local time distance. Then labels will have correct format (such as date/week/month)
|
|
85
|
+
// For example, Amsterdam timezone:
|
|
86
|
+
//
|
|
87
|
+
// 2023-10-28T22:00Z -> Summer time is 2023-10-29T00:00, displays as 29.10.2023
|
|
88
|
+
// 2023-10-29T22:00Z -> Winter time is 2023-10-29T23:00, displays as 23:00
|
|
89
|
+
//
|
|
90
|
+
// Add 1h:
|
|
91
|
+
// 2023-10-29T23:00Z -> Winter time is 2023-10-30T00:00, displays as 30.10.2023
|
|
92
|
+
//
|
|
93
|
+
next = next.add(timeDiff, 'minutes');
|
|
94
|
+
let k = 1;
|
|
95
|
+
while (next.valueOf() <= maxTickValue) {
|
|
96
|
+
// Example of case, Amsterdam timezone:
|
|
97
|
+
// 2023-03-26T00:00Z -> Winter time is 2023-03-26T01:00, displays as 01:00
|
|
98
|
+
// 2023-03-26T01:00Z -> Summer time is 2023-03-26T03:00, displays as 03:00
|
|
99
|
+
// We shift time on -1h... And again:
|
|
100
|
+
// 2023-03-26T00:00Z -> Winter time is 2023-03-26T01:00, displays as 01:00
|
|
101
|
+
// Infinite loop
|
|
102
|
+
//
|
|
103
|
+
// Therefore we need to skip period in the past
|
|
104
|
+
next = next
|
|
105
|
+
.add(tickSize.multiplier * k++, tickSize.period)
|
|
106
|
+
.add(timeDiff, 'minutes');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
cursor = next;
|
|
110
|
+
maxTickValue = Math.max(maxTickValue, cursor.valueOf());
|
|
111
|
+
}
|
|
112
|
+
return ticks;
|
|
113
|
+
}
|
|
114
|
+
export function formatTick(t) {
|
|
115
|
+
let format;
|
|
116
|
+
if (t.valueOf() % MINUTE === 0) {
|
|
117
|
+
if (t.hour() === 0 && t.minute() === 0) {
|
|
118
|
+
if (t.date() === 1) {
|
|
119
|
+
if (t.month() === 0) {
|
|
120
|
+
format = TickFormat.YEAR;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
format = TickFormat.MONTH;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
format = TickFormat.DATE;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
format = TickFormat.MINUTES;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
format = TickFormat.SECONDS;
|
|
136
|
+
}
|
|
137
|
+
return t.format(format);
|
|
138
|
+
}
|
|
139
|
+
export function makeMiddleTicksGeometry({ tickHeight, viewportHeight }) {
|
|
140
|
+
const tickYStart = (viewportHeight - tickHeight) / 2;
|
|
141
|
+
return (x) => `M${x},${tickYStart}l0,${tickHeight}`;
|
|
142
|
+
}
|
|
143
|
+
export function makeSlitTicksGeometry({ tickHeight, viewportHeight }) {
|
|
144
|
+
const slitHeight = viewportHeight - 2 * tickHeight;
|
|
145
|
+
return (x) => `M${x},0l0,${tickHeight}m0,${slitHeight}l0,${tickHeight}`;
|
|
146
|
+
}
|
|
147
|
+
export function makeUnavailableTicksGeometry({ tickHeight, viewportHeight, }) {
|
|
148
|
+
const w = tickHeight;
|
|
149
|
+
const h = viewportHeight;
|
|
150
|
+
return (x) => `M${x},0l${h},${h}l${w},0l${-h},${-h}l${-w},0`;
|
|
151
|
+
}
|
|
152
|
+
export function calculatePosition(value, interval, width) {
|
|
153
|
+
if (!value) {
|
|
154
|
+
return NaN;
|
|
155
|
+
}
|
|
156
|
+
const timeToXCoeff = getLerpCoeff({ start: interval.start.valueOf(), end: interval.end.valueOf() }, { start: 0, end: width });
|
|
157
|
+
return Math.round((value.valueOf() - interval.start.valueOf()) * timeToXCoeff);
|
|
158
|
+
}
|