@windborne/grapher 1.0.21 → 1.0.24
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/26b23c7580ea3345d644.wasm +0 -0
- package/dist/744.bundle.cjs +2 -1
- package/dist/744.bundle.cjs.map +1 -0
- package/dist/744.bundle.esm.js +2 -1
- package/dist/744.bundle.esm.js.map +1 -0
- package/dist/bundle.cjs +1 -1
- package/dist/bundle.cjs.map +1 -1
- package/dist/bundle.esm.js +1 -1
- package/dist/bundle.esm.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +1 -1
- package/src/components/graph_body.jsx +41 -1
- package/src/components/range_graph.jsx +70 -22
- package/src/components/x_axis.jsx +139 -21
- package/src/components/y_axis.jsx +0 -5
- package/src/grapher.jsx +4 -3
- package/src/grapher.scss +84 -43
- package/src/helpers/color_to_vector.js +6 -1
- package/src/helpers/colors.js +82 -16
- package/src/helpers/custom_prop_types.js +2 -1
- package/src/helpers/place_grid.js +219 -0
- package/src/index.d.ts +150 -24
- package/src/renderer/create_gl_program.js +11 -3
- package/src/renderer/draw_area.js +1161 -102
- package/src/renderer/draw_background.js +5 -0
- package/src/renderer/draw_bars.js +100 -11
- package/src/renderer/draw_line.js +338 -38
- package/src/renderer/draw_zero_line.js +5 -0
- package/src/renderer/extract_vertices.js +1 -1
- package/src/renderer/graph_body_renderer.js +278 -17
- package/src/renderer/line.frag +16 -1
- package/src/renderer/line_program.js +200 -10
- package/src/renderer/shadow.frag +98 -0
- package/src/renderer/shadow.vert +20 -0
- package/src/renderer/shadow_program.js +479 -0
- package/src/rust/Cargo.lock +22 -31
- package/src/rust/pkg/grapher_rs.d.ts +6 -0
- package/src/rust/pkg/grapher_rs.js +5 -0
- package/src/rust/pkg/grapher_rs_bg.js +305 -0
- package/src/rust/pkg/grapher_rs_bg.wasm +0 -0
- package/src/rust/pkg/grapher_rs_bg.wasm.d.ts +11 -0
- package/src/rust/pkg/index.js +397 -0
- package/src/state/calculate_tooltip_state.js +6 -6
- package/src/state/state_controller.js +20 -6
package/src/grapher.scss
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
$primary-graph-body-height: 400px,
|
|
3
3
|
$secondary-graph-body-height: 50px,
|
|
4
4
|
|
|
5
|
-
$background-color-1: #
|
|
6
|
-
$background-color-2: #
|
|
5
|
+
$background-color-1: #131313,
|
|
6
|
+
$background-color-2: #1e1e1e,
|
|
7
7
|
|
|
8
8
|
$tooltip-line-color: #CCC,
|
|
9
9
|
$tooltip-background-color: rgba(0, 0, 0, 0.6),
|
|
10
10
|
$tooltip-text-color: #F0F0F0,
|
|
11
11
|
$vertical-line-color: #CCC,
|
|
12
12
|
|
|
13
|
-
$axis-line-color:
|
|
14
|
-
$axis-line-width:
|
|
15
|
-
$axis-tick-color:
|
|
13
|
+
$axis-line-color: rgb(192, 192, 192, 0.3),
|
|
14
|
+
$axis-line-width: 1px,
|
|
15
|
+
$axis-tick-color: rgb(192, 192, 192, 0.3),
|
|
16
16
|
$axis-text-color: #E0E0E3,
|
|
17
17
|
|
|
18
18
|
$range-selection-text-color: silver,
|
|
@@ -24,15 +24,18 @@
|
|
|
24
24
|
$range-selection-button-border: null,
|
|
25
25
|
$range-selection-selected-button-border: null,
|
|
26
26
|
|
|
27
|
-
$range-graph-selection-
|
|
27
|
+
$range-graph-selection-background-color: rgba(0, 0, 0, 0.3),
|
|
28
28
|
$range-graph-selection-range-color: rgba(255, 255, 255, 0.1),
|
|
29
29
|
$range-graph-selection-outline-color: #AAA,
|
|
30
30
|
$range-graph-selection-bar-color: #808083,
|
|
31
31
|
$range-graph-selection-bar-track-color: #303033,
|
|
32
32
|
$range-graph-selection-bar-rifles-color: #FFF,
|
|
33
|
+
$range-graph-selection-bar-height: 14px,
|
|
33
34
|
$range-graph-handle-color: #AAA,
|
|
34
35
|
$range-graph-handle-fill-color: #666,
|
|
35
36
|
$range-graph-axis-text-color: #9f9f9f,
|
|
37
|
+
$range-graph-tick-highlighted-color: #FFF,
|
|
38
|
+
$range-graph-text-highlighted-color: #FFF,
|
|
36
39
|
|
|
37
40
|
$annotation-background-color: rgba(255, 255, 255, 0.3),
|
|
38
41
|
|
|
@@ -52,6 +55,7 @@
|
|
|
52
55
|
$new-grapher-color: #DDD
|
|
53
56
|
) {
|
|
54
57
|
$x-axis-height: 20px;
|
|
58
|
+
$x-axis-dual-height: 30px;
|
|
55
59
|
$padding: 10px;
|
|
56
60
|
|
|
57
61
|
$axis-z-index: 0;
|
|
@@ -431,6 +435,7 @@
|
|
|
431
435
|
|
|
432
436
|
.range-graph-container {
|
|
433
437
|
display: flex;
|
|
438
|
+
margin-top: 10px;
|
|
434
439
|
}
|
|
435
440
|
|
|
436
441
|
.graph-body {
|
|
@@ -580,25 +585,11 @@
|
|
|
580
585
|
&.x-axis {
|
|
581
586
|
width: 1px;
|
|
582
587
|
height: $x-axis-height;
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
text {
|
|
587
|
-
text-anchor: middle;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
&.axis-item-first {
|
|
591
|
-
text {
|
|
592
|
-
text-anchor: start;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
&.axis-item-last {
|
|
597
|
-
text {
|
|
598
|
-
text-anchor: end;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
588
|
+
|
|
589
|
+
&.x-axis-dual {
|
|
590
|
+
height: $x-axis-dual-height;
|
|
601
591
|
}
|
|
592
|
+
display: block;
|
|
602
593
|
}
|
|
603
594
|
|
|
604
595
|
&.y-axis {
|
|
@@ -606,7 +597,6 @@
|
|
|
606
597
|
|
|
607
598
|
.axis-item text {
|
|
608
599
|
text-anchor: end;
|
|
609
|
-
alignment-baseline: middle;
|
|
610
600
|
}
|
|
611
601
|
|
|
612
602
|
.y-axis-label {
|
|
@@ -634,11 +624,6 @@
|
|
|
634
624
|
stroke-width: $axis-line-width;
|
|
635
625
|
}
|
|
636
626
|
|
|
637
|
-
.axis-line-shadow {
|
|
638
|
-
stroke: $axis-tick-color;
|
|
639
|
-
stroke-width: 1px;
|
|
640
|
-
}
|
|
641
|
-
|
|
642
627
|
.axis-item {
|
|
643
628
|
path {
|
|
644
629
|
stroke: $axis-tick-color;
|
|
@@ -652,7 +637,7 @@
|
|
|
652
637
|
|
|
653
638
|
&.axis-item-major {
|
|
654
639
|
.axis-tick {
|
|
655
|
-
stroke-width:
|
|
640
|
+
stroke-width: 1px;
|
|
656
641
|
}
|
|
657
642
|
}
|
|
658
643
|
|
|
@@ -666,15 +651,19 @@
|
|
|
666
651
|
|
|
667
652
|
.range-selection-graph {
|
|
668
653
|
width: 100%;
|
|
669
|
-
|
|
654
|
+
background-color: $range-graph-selection-background-color;
|
|
655
|
+
height: calc(#{$secondary-graph-body-height} + #{$range-graph-selection-bar-height});
|
|
670
656
|
|
|
671
657
|
.graph-body-secondary {
|
|
672
658
|
height: $secondary-graph-body-height;
|
|
673
659
|
|
|
660
|
+
canvas {
|
|
661
|
+
height: 100%;
|
|
662
|
+
}
|
|
663
|
+
|
|
674
664
|
svg {
|
|
675
665
|
position: absolute;
|
|
676
666
|
left: 0;
|
|
677
|
-
height: $secondary-graph-body-height;
|
|
678
667
|
width: 100%;
|
|
679
668
|
overflow: visible;
|
|
680
669
|
|
|
@@ -683,31 +672,65 @@
|
|
|
683
672
|
cursor: ew-resize;
|
|
684
673
|
}
|
|
685
674
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
675
|
+
|
|
676
|
+
.target-selection-outline {
|
|
677
|
+
stroke: $range-graph-selection-outline-color;
|
|
678
|
+
fill: none;
|
|
689
679
|
}
|
|
690
680
|
|
|
691
681
|
.selection-bar-track {
|
|
692
682
|
fill: $range-graph-selection-bar-track-color;
|
|
693
683
|
}
|
|
694
684
|
|
|
685
|
+
.selection-bar {
|
|
686
|
+
fill: $range-graph-selection-bar-color;
|
|
687
|
+
cursor: ew-resize;
|
|
688
|
+
}
|
|
689
|
+
|
|
695
690
|
.selection-bar-rifles {
|
|
696
|
-
fill: none;
|
|
697
|
-
stroke-width: 1;
|
|
698
691
|
stroke: $range-graph-selection-bar-rifles-color;
|
|
692
|
+
stroke-width: 1px;
|
|
693
|
+
cursor: ew-resize;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.selection-bar-handle-hit {
|
|
697
|
+
cursor: ew-resize;
|
|
699
698
|
}
|
|
700
699
|
|
|
701
700
|
.selection-bar-handle {
|
|
702
701
|
stroke: $range-graph-handle-color;
|
|
703
|
-
stroke-width: 1;
|
|
704
702
|
fill: $range-graph-handle-fill-color;
|
|
703
|
+
stroke-width: 1px;
|
|
705
704
|
cursor: ew-resize;
|
|
705
|
+
transition: stroke-width 0.15s ease, fill 0.15s ease;
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
-
.
|
|
709
|
-
|
|
710
|
-
|
|
708
|
+
.selection-handle {
|
|
709
|
+
.selection-handle-hit {
|
|
710
|
+
cursor: ew-resize;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.selection-handle-line {
|
|
714
|
+
stroke: $range-graph-handle-color;
|
|
715
|
+
stroke-width: 1;
|
|
716
|
+
transition: stroke-width 0.15s ease;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
&:hover .selection-handle-line {
|
|
720
|
+
stroke-width: 3;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
&.selection-handle-dragging .selection-handle-line {
|
|
724
|
+
stroke-width: 3;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
&:hover .selection-bar-handle {
|
|
728
|
+
stroke-width: 2px;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
&.selection-handle-dragging .selection-bar-handle {
|
|
732
|
+
stroke-width: 2px;
|
|
733
|
+
}
|
|
711
734
|
}
|
|
712
735
|
|
|
713
736
|
.axis-item {
|
|
@@ -720,9 +743,19 @@
|
|
|
720
743
|
}
|
|
721
744
|
|
|
722
745
|
path {
|
|
723
|
-
stroke: $axis-
|
|
746
|
+
stroke: $range-graph-axis-text-color;
|
|
724
747
|
stroke-width: 1px;
|
|
725
748
|
}
|
|
749
|
+
|
|
750
|
+
&.axis-item-highlighted {
|
|
751
|
+
path {
|
|
752
|
+
stroke: $range-graph-tick-highlighted-color;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
text {
|
|
756
|
+
fill: $range-graph-text-highlighted-color;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
726
759
|
}
|
|
727
760
|
}
|
|
728
761
|
}
|
|
@@ -841,8 +874,12 @@
|
|
|
841
874
|
$range-graph-selection-bar-color: #B0B0B7,
|
|
842
875
|
$range-graph-selection-bar-track-color: #EEE,
|
|
843
876
|
$range-graph-selection-bar-rifles-color: #333,
|
|
877
|
+
$range-graph-selection-bar-height: 14px,
|
|
844
878
|
$range-graph-handle-color: #333,
|
|
845
879
|
$range-graph-handle-fill-color: #B0B0B7,
|
|
880
|
+
$range-graph-axis-text-color: #555,
|
|
881
|
+
$range-graph-tick-highlighted-color: #000,
|
|
882
|
+
$range-graph-text-highlighted-color: #000,
|
|
846
883
|
|
|
847
884
|
$annotation-background-color: rgba(0, 0, 0, 0.3),
|
|
848
885
|
|
|
@@ -898,8 +935,12 @@
|
|
|
898
935
|
$range-graph-selection-bar-color: #B0B0B7,
|
|
899
936
|
$range-graph-selection-bar-track-color: #EEE,
|
|
900
937
|
$range-graph-selection-bar-rifles-color: #333,
|
|
938
|
+
$range-graph-selection-bar-height: 14px,
|
|
901
939
|
$range-graph-handle-color: #333,
|
|
902
940
|
$range-graph-handle-fill-color: #B0B0B7,
|
|
941
|
+
$range-graph-axis-text-color: #333,
|
|
942
|
+
$range-graph-tick-highlighted-color: #000,
|
|
943
|
+
$range-graph-text-highlighted-color: #000,
|
|
903
944
|
|
|
904
945
|
$annotation-background-color: rgba(0, 0, 0, 0.3),
|
|
905
946
|
|
|
@@ -23,10 +23,15 @@ export default function colorToVector(color) {
|
|
|
23
23
|
];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
if (typeof color !== 'string' || !/^#[\dA-F]{6}$/i.test(color)) {
|
|
26
|
+
if (typeof color !== 'string' || !/^#[\dA-F]{3}$|^#[\dA-F]{6}$/i.test(color)) {
|
|
27
27
|
throw new Error(`Color must be a hex string: ${color}`);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
// support for short hex codes, expanding 3-digit hex to 6-digit
|
|
31
|
+
if (color.length === 4) {
|
|
32
|
+
color = '#' + color[1] + color[1] + color[2] + color[2] + color[3] + color[3];
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
const r = parseInt(color.substr(1, 2), 16)/255;
|
|
31
36
|
const g = parseInt(color.substr(3, 2), 16)/255;
|
|
32
37
|
const b = parseInt(color.substr(5, 2), 16)/255;
|
package/src/helpers/colors.js
CHANGED
|
@@ -1,27 +1,93 @@
|
|
|
1
1
|
export const LINE_COLORS = [
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
"#F1C232",
|
|
3
|
+
"#1259f8",
|
|
4
|
+
"#cb4b4b",
|
|
5
|
+
"#4da74d",
|
|
6
|
+
"#9440ed",
|
|
7
|
+
"#61e0ed",
|
|
8
|
+
"#ed6d2c",
|
|
9
|
+
"#ed13c6",
|
|
10
|
+
"#bbed59",
|
|
11
11
|
];
|
|
12
12
|
|
|
13
13
|
export default function getColor(seriesColor, i, multigrapherSeriesIndex) {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
if (typeof seriesColor === "string") {
|
|
15
|
+
return seriesColor;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (typeof seriesColor === "number") {
|
|
19
|
+
return LINE_COLORS[seriesColor % LINE_COLORS.length];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (multigrapherSeriesIndex !== undefined) {
|
|
23
|
+
return LINE_COLORS[multigrapherSeriesIndex % LINE_COLORS.length];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return LINE_COLORS[i % LINE_COLORS.length];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Applies reduced opacity to a color
|
|
31
|
+
* @param {string} color
|
|
32
|
+
* @param {number} opacityFactor
|
|
33
|
+
* @returns {string}
|
|
34
|
+
*/
|
|
35
|
+
export function applyReducedOpacity(color, opacityFactor) {
|
|
36
|
+
if (!color) return color;
|
|
37
|
+
|
|
38
|
+
if (color.startsWith("rgba(")) {
|
|
39
|
+
const matches = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/);
|
|
40
|
+
if (matches) {
|
|
41
|
+
const [, r, g, b, a] = matches;
|
|
42
|
+
const newAlpha = parseFloat(a) * opacityFactor;
|
|
43
|
+
return `rgba(${r}, ${g}, ${b}, ${newAlpha})`;
|
|
16
44
|
}
|
|
45
|
+
}
|
|
17
46
|
|
|
18
|
-
|
|
19
|
-
|
|
47
|
+
if (color.startsWith("rgb(")) {
|
|
48
|
+
const matches = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
|
49
|
+
if (matches) {
|
|
50
|
+
const [, r, g, b] = matches;
|
|
51
|
+
return `rgba(${r}, ${g}, ${b}, ${opacityFactor})`;
|
|
20
52
|
}
|
|
53
|
+
}
|
|
21
54
|
|
|
22
|
-
|
|
23
|
-
|
|
55
|
+
if (color.startsWith("#")) {
|
|
56
|
+
let hex = color.slice(1);
|
|
57
|
+
if (hex.length === 3) {
|
|
58
|
+
hex = hex
|
|
59
|
+
.split("")
|
|
60
|
+
.map((char) => char + char)
|
|
61
|
+
.join("");
|
|
24
62
|
}
|
|
63
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
64
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
65
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
66
|
+
return `rgba(${r}, ${g}, ${b}, ${opacityFactor})`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return color;
|
|
70
|
+
}
|
|
25
71
|
|
|
26
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Applies reduced opacity to a gradient
|
|
74
|
+
* @param {Array<[number, string]>} gradient
|
|
75
|
+
* @param {number} opacityFactor
|
|
76
|
+
* @returns {Array<[number, string]>}
|
|
77
|
+
*/
|
|
78
|
+
export function applyReducedOpacityToGradient(gradient, opacityFactor) {
|
|
79
|
+
if (!gradient || !Array.isArray(gradient)) {
|
|
80
|
+
return gradient;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return gradient.map((stop) => {
|
|
84
|
+
if (Array.isArray(stop) && stop.length === 2) {
|
|
85
|
+
const [position, color] = stop;
|
|
86
|
+
const translucentColor = applyReducedOpacity(color, opacityFactor);
|
|
87
|
+
return [position, translucentColor];
|
|
88
|
+
} else if (typeof stop === "string") {
|
|
89
|
+
return applyReducedOpacity(stop, opacityFactor);
|
|
90
|
+
}
|
|
91
|
+
return stop;
|
|
92
|
+
});
|
|
27
93
|
}
|
|
@@ -65,7 +65,7 @@ const SingleSeries = PropTypes.shape({
|
|
|
65
65
|
background: PropTypes.object,
|
|
66
66
|
hideFromKey: PropTypes.bool,
|
|
67
67
|
showIndividualPoints: PropTypes.bool,
|
|
68
|
-
rendering: PropTypes.oneOf(['line', 'bar', 'area']), // defaults to line
|
|
68
|
+
rendering: PropTypes.oneOf(['line', 'bar', 'area', 'shadow']), // defaults to line
|
|
69
69
|
negativeColor: PropTypes.string, // only applies to bar
|
|
70
70
|
gradient: PropTypes.array, // only applies to area
|
|
71
71
|
zeroLineWidth: PropTypes.number, // only applies to bar and area
|
|
@@ -75,6 +75,7 @@ const SingleSeries = PropTypes.shape({
|
|
|
75
75
|
tooltipWidth: PropTypes.number,
|
|
76
76
|
hasAreaBottom: PropTypes.bool,
|
|
77
77
|
shadowColor: PropTypes.string,
|
|
78
|
+
gradient: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.array])), // gradient colors or [position, color] pairs
|
|
78
79
|
rangeKey: PropTypes.string
|
|
79
80
|
});
|
|
80
81
|
|
|
@@ -248,6 +248,225 @@ function placeDatesGrid({ min, max, precision, expectedLabelSize, labelPadding,
|
|
|
248
248
|
return ticks.filter(({ pixelValue }) => pixelValue <= totalSize && pixelValue >= 0);
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
function placeTimeOnlyGrid({ min, max, precision, expectedLabelSize, labelPadding, totalSize, skipFirst=false, skipLast=false, scale='linear', formatter, inverted=false, formatOptions={} }) {
|
|
252
|
+
const paddedLabelSize = expectedLabelSize + 2*labelPadding;
|
|
253
|
+
const ticks = [];
|
|
254
|
+
const placementParams = { scale, min, max, inverted, totalSize, precision, formatter, formatOptions, dates: true };
|
|
255
|
+
|
|
256
|
+
const desiredCount = Math.floor(totalSize/paddedLabelSize);
|
|
257
|
+
const span = max - min;
|
|
258
|
+
|
|
259
|
+
let unit, amount;
|
|
260
|
+
|
|
261
|
+
const hourSpan = span / (60 * 60 * 1000);
|
|
262
|
+
const minuteSpan = span / (60 * 1000);
|
|
263
|
+
|
|
264
|
+
if (hourSpan <= desiredCount * 8) {
|
|
265
|
+
unit = 'h';
|
|
266
|
+
amount = Math.max(1, Math.ceil(hourSpan / desiredCount));
|
|
267
|
+
if (amount <= 6) {
|
|
268
|
+
} else if (amount <= 12) {
|
|
269
|
+
amount = 12;
|
|
270
|
+
} else if (amount <= 24) {
|
|
271
|
+
amount = 24;
|
|
272
|
+
} else {
|
|
273
|
+
amount = Math.ceil(amount / 24) * 24;
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
unit = 'h';
|
|
277
|
+
amount = 24;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (!skipFirst) {
|
|
281
|
+
ticks.push(placeTickByPixel(0, {...placementParams, justTime: true}, {position: 'first'}));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let currentDate = new Date(min);
|
|
285
|
+
|
|
286
|
+
if (unit === 'h') {
|
|
287
|
+
currentDate.setMinutes(0, 0, 0);
|
|
288
|
+
if (amount === 24) {
|
|
289
|
+
currentDate.setHours(0);
|
|
290
|
+
} else if (amount === 12) {
|
|
291
|
+
const currentHour = currentDate.getHours();
|
|
292
|
+
const alignedHour = currentHour < 12 ? 0 : 12;
|
|
293
|
+
currentDate.setHours(alignedHour);
|
|
294
|
+
} else {
|
|
295
|
+
const currentHour = currentDate.getHours();
|
|
296
|
+
const alignedHour = Math.floor(currentHour / amount) * amount;
|
|
297
|
+
currentDate.setHours(alignedHour);
|
|
298
|
+
}
|
|
299
|
+
} else if (unit === 'm') {
|
|
300
|
+
currentDate.setSeconds(0, 0);
|
|
301
|
+
const currentMinute = currentDate.getMinutes();
|
|
302
|
+
const alignedMinute = Math.floor(currentMinute / amount) * amount;
|
|
303
|
+
currentDate.setMinutes(alignedMinute);
|
|
304
|
+
} else if (unit === 's') {
|
|
305
|
+
currentDate.setMilliseconds(0);
|
|
306
|
+
const currentSecond = currentDate.getSeconds();
|
|
307
|
+
const alignedSecond = Math.floor(currentSecond / amount) * amount;
|
|
308
|
+
currentDate.setSeconds(alignedSecond);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
while (currentDate < min) {
|
|
312
|
+
if (unit === 'h') {
|
|
313
|
+
currentDate = new Date(currentDate.valueOf() + amount * 60 * 60 * 1000);
|
|
314
|
+
} else if (unit === 'm') {
|
|
315
|
+
currentDate = new Date(currentDate.valueOf() + amount * 60 * 1000);
|
|
316
|
+
} else if (unit === 's') {
|
|
317
|
+
currentDate = new Date(currentDate.valueOf() + amount * 1000);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
while (currentDate < max) {
|
|
322
|
+
const tick = placeTick(currentDate, {...placementParams, justTime: true});
|
|
323
|
+
|
|
324
|
+
const reservedSpaceForLast = expectedLabelSize + labelPadding;
|
|
325
|
+
const maxPixelForMiddleTicks = totalSize - reservedSpaceForLast;
|
|
326
|
+
|
|
327
|
+
if (ticks.length && (tick.pixelValue - ticks[ticks.length - 1].pixelValue) < (expectedLabelSize + labelPadding)) {
|
|
328
|
+
} else if (tick.pixelValue + expectedLabelSize < maxPixelForMiddleTicks) {
|
|
329
|
+
ticks.push(tick);
|
|
330
|
+
} else {
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (unit === 'h') {
|
|
335
|
+
currentDate = new Date(currentDate.valueOf() + amount * 60 * 60 * 1000);
|
|
336
|
+
} else if (unit === 'm') {
|
|
337
|
+
currentDate = new Date(currentDate.valueOf() + amount * 60 * 1000);
|
|
338
|
+
} else if (unit === 's') {
|
|
339
|
+
currentDate = new Date(currentDate.valueOf() + amount * 1000);
|
|
340
|
+
} else {
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (!skipLast) {
|
|
346
|
+
const lastTick = placeTick(max, {...placementParams, justTime: true}, {position: 'last'});
|
|
347
|
+
if (ticks.length === 0 || (lastTick.pixelValue - ticks[ticks.length - 1].pixelValue) >= (expectedLabelSize + labelPadding/2)) {
|
|
348
|
+
ticks.push(lastTick);
|
|
349
|
+
} else {
|
|
350
|
+
ticks[ticks.length - 1] = lastTick;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return ticks.filter(({ pixelValue }) => pixelValue <= totalSize && pixelValue >= 0);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function placeDateOnlyGrid({ min, max, precision, expectedLabelSize, labelPadding, totalSize, skipFirst=false, skipLast=false, scale='linear', formatter, inverted=false, formatOptions={} }) {
|
|
358
|
+
const paddedLabelSize = expectedLabelSize + 2*labelPadding;
|
|
359
|
+
const ticks = [];
|
|
360
|
+
|
|
361
|
+
const minYear = new Date(min).getFullYear();
|
|
362
|
+
const maxYear = new Date(max).getFullYear();
|
|
363
|
+
const spanMultipleYears = minYear !== maxYear;
|
|
364
|
+
|
|
365
|
+
const customDateFormatter = (date, options) => {
|
|
366
|
+
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
367
|
+
const d = new Date(date);
|
|
368
|
+
const month = monthNames[d.getMonth()];
|
|
369
|
+
const day = d.getDate();
|
|
370
|
+
const year = d.getFullYear();
|
|
371
|
+
|
|
372
|
+
if (spanMultipleYears) {
|
|
373
|
+
return `${month} ${day} ${year}`;
|
|
374
|
+
} else {
|
|
375
|
+
return `${month} ${day}`;
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const placementParams = { scale, min, max, inverted, totalSize, precision, formatter: customDateFormatter, formatOptions, dates: true };
|
|
380
|
+
|
|
381
|
+
const span = max - min;
|
|
382
|
+
const hourSpan = span / (60 * 60 * 1000);
|
|
383
|
+
|
|
384
|
+
let { amount, unit } = getEvenDateTickSpacing(span, totalSize/paddedLabelSize, formatOptions.unitOverride);
|
|
385
|
+
|
|
386
|
+
if ((unit === 'h' || unit === 'm' || unit === 's') && hourSpan >= 48) {
|
|
387
|
+
unit = 'd';
|
|
388
|
+
amount = Math.max(1, Math.ceil(hourSpan / 24 / Math.floor(totalSize/paddedLabelSize)));
|
|
389
|
+
} else if ((unit === 'h' || unit === 'm' || unit === 's') && hourSpan < 48) {
|
|
390
|
+
const startTick = placeTick(min, {...placementParams, justDate: true}, {position: 'first'});
|
|
391
|
+
const endTick = placeTick(max, {...placementParams, justDate: true}, {position: 'last'});
|
|
392
|
+
|
|
393
|
+
const ticks = [startTick];
|
|
394
|
+
if ((endTick.pixelValue - startTick.pixelValue) >= (expectedLabelSize + labelPadding)) {
|
|
395
|
+
ticks.push(endTick);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return ticks.filter(({ pixelValue }) => pixelValue <= totalSize && pixelValue >= 0);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (!skipFirst) {
|
|
402
|
+
ticks.push(placeTickByPixel(0, {...placementParams, justDate: true}, {position: 'first'}));
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
let currentDate = new Date(min);
|
|
406
|
+
|
|
407
|
+
if (unit === 'month') {
|
|
408
|
+
currentDate = startOfDayInTimezone(currentDate, formatOptions.timeZone);
|
|
409
|
+
currentDate.setDate(1);
|
|
410
|
+
} else if (unit === 'd') {
|
|
411
|
+
currentDate = startOfDayInTimezone(currentDate, formatOptions.timeZone);
|
|
412
|
+
currentDate.setHours(0, 0, 0, 0);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
while (currentDate < max) {
|
|
416
|
+
let delta = 24*60*60*1000;
|
|
417
|
+
|
|
418
|
+
if (unit === 'month') {
|
|
419
|
+
delta = 0;
|
|
420
|
+
if (currentDate.getMonth() === 11) {
|
|
421
|
+
currentDate = new Date(currentDate.getFullYear() + 1, 0, 1);
|
|
422
|
+
} else {
|
|
423
|
+
currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1);
|
|
424
|
+
}
|
|
425
|
+
} else if (unit === 'year') {
|
|
426
|
+
currentDate = new Date(currentDate.getFullYear() + 1, 0, 1);
|
|
427
|
+
delta = 0;
|
|
428
|
+
} else if (unit === 'd') {
|
|
429
|
+
delta = amount * 24 * 60 * 60 * 1000;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (delta > 0) {
|
|
433
|
+
currentDate = new Date(currentDate.valueOf() + delta);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const tick = placeTick(currentDate, {...placementParams, justDate: true});
|
|
437
|
+
|
|
438
|
+
const reservedSpaceForLast = expectedLabelSize + labelPadding;
|
|
439
|
+
const maxPixelForMiddleTicks = totalSize - reservedSpaceForLast;
|
|
440
|
+
|
|
441
|
+
if (ticks.length && (tick.pixelValue - ticks[ticks.length - 1].pixelValue) < (expectedLabelSize + (labelPadding || 0))) {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (tick.pixelValue + expectedLabelSize < maxPixelForMiddleTicks) {
|
|
446
|
+
ticks.push(tick);
|
|
447
|
+
} else {
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (!skipLast) {
|
|
453
|
+
const lastTick = placeTick(max, {...placementParams, justDate: true}, {position: 'last'});
|
|
454
|
+
if (ticks.length === 0 || (lastTick.pixelValue - ticks[ticks.length - 1].pixelValue) >= (expectedLabelSize + labelPadding/2)) {
|
|
455
|
+
ticks.push(lastTick);
|
|
456
|
+
} else {
|
|
457
|
+
ticks[ticks.length - 1] = lastTick;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (ticks.length === 0 && hourSpan >= 48) {
|
|
462
|
+
ticks.push(placeTickByPixel(0, {...placementParams, justDate: true}, {position: 'first'}));
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return ticks.filter(({ pixelValue }) => pixelValue <= totalSize && pixelValue >= 0);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export { placeTimeOnlyGrid, placeDateOnlyGrid };
|
|
469
|
+
|
|
251
470
|
export default function placeGrid(opts) {
|
|
252
471
|
if (opts.dates) {
|
|
253
472
|
return placeDatesGrid(opts);
|