@internetarchive/histogram-date-range 0.0.10-beta → 0.1.1-alpha
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/demo/index.css +23 -0
- package/demo/index.html +52 -43
- package/dist/src/histogram-date-range.d.ts +7 -5
- package/dist/src/histogram-date-range.js +114 -59
- package/dist/src/histogram-date-range.js.map +1 -1
- package/dist/test/histogram-date-range.test.js +109 -35
- package/dist/test/histogram-date-range.test.js.map +1 -1
- package/docs/_snowpack/pkg/common/lit-html-bb3fcd20.js +8 -0
- package/docs/_snowpack/pkg/dayjs/esm/plugin/customParseFormat.js +327 -0
- package/docs/_snowpack/pkg/import-map.json +1 -0
- package/docs/_snowpack/pkg/lit/decorators.js +8 -2
- package/docs/_snowpack/pkg/lit/directives/live.js +4 -4
- package/docs/_snowpack/pkg/lit.js +6 -6
- package/docs/demo/index.css +23 -0
- package/docs/demo/index.html +52 -43
- package/docs/dist/src/histogram-date-range.js +92 -50
- package/package.json +3 -3
- package/src/histogram-date-range.ts +150 -66
- package/test/histogram-date-range.test.ts +140 -37
- package/docs/_snowpack/pkg/common/lit-html-e67c9f49.js +0 -8
- package/types/static.d.ts +0 -4
package/demo/index.css
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
html {
|
|
2
|
+
font-size: 10px;
|
|
3
|
+
font-family: sans-serif;
|
|
4
|
+
}
|
|
5
|
+
body {
|
|
6
|
+
background: white;
|
|
7
|
+
}
|
|
8
|
+
.container {
|
|
9
|
+
margin-top: 20px;
|
|
10
|
+
display: grid;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
}
|
|
13
|
+
.description {
|
|
14
|
+
margin: 10px auto;
|
|
15
|
+
}
|
|
16
|
+
.received-events {
|
|
17
|
+
position: absolute;
|
|
18
|
+
top: 0;
|
|
19
|
+
}
|
|
20
|
+
button {
|
|
21
|
+
font-size: 100%;
|
|
22
|
+
margin: 10px auto;
|
|
23
|
+
}
|
package/demo/index.html
CHANGED
|
@@ -3,49 +3,29 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
5
5
|
<meta charset="utf-8" />
|
|
6
|
-
<
|
|
7
|
-
html {
|
|
8
|
-
font-size: 10px;
|
|
9
|
-
font-family: sans-serif;
|
|
10
|
-
}
|
|
11
|
-
body {
|
|
12
|
-
background: white;
|
|
13
|
-
}
|
|
14
|
-
.container {
|
|
15
|
-
margin-top: 50px;
|
|
16
|
-
display: grid;
|
|
17
|
-
justify-content: center;
|
|
18
|
-
}
|
|
19
|
-
.description {
|
|
20
|
-
margin: 10px auto;
|
|
21
|
-
}
|
|
22
|
-
.received-events {
|
|
23
|
-
position: absolute;
|
|
24
|
-
top: 0;
|
|
25
|
-
}
|
|
26
|
-
button {
|
|
27
|
-
font-size: 100%;
|
|
28
|
-
margin: 10px auto;
|
|
29
|
-
}
|
|
30
|
-
</style>
|
|
6
|
+
<link rel="stylesheet" href="index.css">
|
|
31
7
|
</head>
|
|
32
8
|
|
|
33
9
|
<script type="module">
|
|
34
10
|
import '../dist/src/histogram-date-range.js';
|
|
11
|
+
let eventCount = 0;
|
|
35
12
|
// listen to events from the component and display the data received from them
|
|
36
13
|
document.addEventListener('histogramDateRangeUpdated', e => {
|
|
37
|
-
document.querySelector('.received-events').innerHTML
|
|
38
|
-
|
|
14
|
+
document.querySelector('.received-events').innerHTML =
|
|
15
|
+
++eventCount + ': ' + JSON.stringify(e.detail);
|
|
39
16
|
});
|
|
40
17
|
</script>
|
|
41
18
|
<body>
|
|
42
19
|
<pre class="received-events"></pre>
|
|
43
20
|
|
|
44
21
|
<div class="container">
|
|
45
|
-
<div class="description">
|
|
22
|
+
<div class="description">
|
|
23
|
+
pre-selected range with 1000ms debounce delay
|
|
24
|
+
</div>
|
|
46
25
|
<histogram-date-range
|
|
47
26
|
minDate="1400"
|
|
48
27
|
maxDate="2021"
|
|
28
|
+
updateDelay="1000"
|
|
49
29
|
minSelectedDate="1800"
|
|
50
30
|
maxSelectedDate="1900"
|
|
51
31
|
bins="[ 74, 67, 17, 66, 49, 93, 47, 61, 32, 46, 53, 2,
|
|
@@ -57,19 +37,45 @@
|
|
|
57
37
|
</div>
|
|
58
38
|
|
|
59
39
|
<div class="container">
|
|
60
|
-
<div class="description">
|
|
40
|
+
<div class="description">range spanning negative to positive years</div>
|
|
41
|
+
<histogram-date-range
|
|
42
|
+
mindate="-1050" maxdate="2200"
|
|
43
|
+
bins="[ 74, 67, 17, 66, 49, 93, 47, 61, 32, 46, 53, 2,
|
|
44
|
+
13, 45, 28, 1, 8, 70, 37, 74, 67, 17, 66, 49, 93,
|
|
45
|
+
47, 61, 70, 37, 74, 67, 17, 66, 49, 93, 47, 61, 32,
|
|
46
|
+
32, 70, 37, 74, 67, 17, 66, 49, 93, 47, 61, 32
|
|
47
|
+
]"
|
|
48
|
+
></histogram-date-range>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
<div class="container">
|
|
54
|
+
<div class="description">small year range and few bins</div>
|
|
55
|
+
<histogram-date-range width="175" tooltipwidth="120"
|
|
56
|
+
mindate="2008" maxdate="2016" bins="[76104,866978,1151617,986331,218672,107410,3324]">
|
|
57
|
+
</histogram-date-range>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div class="container">
|
|
61
|
+
<div class="description">
|
|
62
|
+
default range with custom styling and date format
|
|
63
|
+
</div>
|
|
61
64
|
<histogram-date-range
|
|
62
65
|
width="300"
|
|
63
66
|
height="50"
|
|
64
67
|
tooltipWidth="140"
|
|
65
|
-
updateDelay="2000"
|
|
66
68
|
dateFormat="DD MMM YYYY"
|
|
67
69
|
style="
|
|
70
|
+
--histogramDateRangeSliderColor: #d8b384;
|
|
71
|
+
--histogramDateRangeSelectedRangeColor: #f3f0d7;
|
|
72
|
+
--histogramDateRangeTooltipFontFamily: serif;
|
|
73
|
+
--histogramDateRangeInputFontFamily: serif;
|
|
68
74
|
--histogramDateRangeTooltipFontSize: 1rem;
|
|
69
75
|
--histogramDateRangeInputWidth: 85px;
|
|
70
76
|
"
|
|
71
|
-
minDate="May
|
|
72
|
-
maxDate="
|
|
77
|
+
minDate="05 May 1972"
|
|
78
|
+
maxDate="21 Dec 1980"
|
|
73
79
|
bins="[ 85, 25, 200, 0, 0, 34, 0, 2, 5, 10, 0, 56, 10, 45, 100, 70, 50 ]"
|
|
74
80
|
></histogram-date-range>
|
|
75
81
|
</div>
|
|
@@ -99,11 +105,8 @@
|
|
|
99
105
|
</script>
|
|
100
106
|
|
|
101
107
|
<div class="container">
|
|
102
|
-
<div class="description">data set up with js
|
|
103
|
-
<histogram-date-range
|
|
104
|
-
id="js-setup"
|
|
105
|
-
updateDelay="0"
|
|
106
|
-
></histogram-date-range>
|
|
108
|
+
<div class="description">data set up with js</div>
|
|
109
|
+
<histogram-date-range id="js-setup"></histogram-date-range>
|
|
107
110
|
</div>
|
|
108
111
|
<script>
|
|
109
112
|
document.addEventListener('DOMContentLoaded', function () {
|
|
@@ -112,17 +115,23 @@
|
|
|
112
115
|
);
|
|
113
116
|
histogram.minDate = '1950';
|
|
114
117
|
histogram.maxDate = '2000';
|
|
115
|
-
// generate
|
|
118
|
+
// generate array of [0, 1, 2, ... 49]
|
|
116
119
|
histogram.bins = [...Array(50).keys()];
|
|
117
120
|
});
|
|
118
121
|
</script>
|
|
119
122
|
|
|
123
|
+
<!-- <div class="container">
|
|
124
|
+
<div class="description">
|
|
125
|
+
single bin
|
|
126
|
+
</div>
|
|
127
|
+
<histogram-date-range mindate="1926" maxdate="1926" bins="[8]">
|
|
128
|
+
</histogram-date-range>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
120
131
|
<div class="container">
|
|
121
132
|
<div class="description">empty data</div>
|
|
122
|
-
<histogram-date-range
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
></histogram-date-range>
|
|
126
|
-
</div>
|
|
133
|
+
<histogram-date-range missingDataMessage="no data..."></histoghistogram-date-range>
|
|
134
|
+
</div> -->
|
|
135
|
+
|
|
127
136
|
</body>
|
|
128
137
|
</html>
|
|
@@ -47,9 +47,11 @@ export declare class HistogramDateRange extends LitElement {
|
|
|
47
47
|
set loading(value: boolean);
|
|
48
48
|
/** formatted minimum date of selected date range */
|
|
49
49
|
get minSelectedDate(): string;
|
|
50
|
+
/** updates minSelectedDate if new date is valid */
|
|
50
51
|
set minSelectedDate(rawDate: string);
|
|
51
52
|
/** formatted maximum date of selected date range */
|
|
52
53
|
get maxSelectedDate(): string;
|
|
54
|
+
/** updates maxSelectedDate if new date is valid */
|
|
53
55
|
set maxSelectedDate(rawDate: string);
|
|
54
56
|
/** horizontal position of min date slider */
|
|
55
57
|
get minSliderX(): number;
|
|
@@ -110,13 +112,13 @@ export declare class HistogramDateRange extends LitElement {
|
|
|
110
112
|
* @returns x-position of slider
|
|
111
113
|
*/
|
|
112
114
|
private translateDateToPosition;
|
|
115
|
+
/** ensure that the returned value is between minValue and maxValue */
|
|
116
|
+
private clamp;
|
|
113
117
|
private handleMinDateInput;
|
|
114
118
|
private handleMaxDateInput;
|
|
119
|
+
private handleKeyUp;
|
|
115
120
|
private get currentDateRangeString();
|
|
116
|
-
|
|
117
|
-
private get minSelectedDateMS();
|
|
118
|
-
/** maximum selected date in milliseconds */
|
|
119
|
-
private get maxSelectedDateMS();
|
|
121
|
+
private getMSFromString;
|
|
120
122
|
private handleBarClick;
|
|
121
123
|
private get minSliderTemplate();
|
|
122
124
|
private get maxSliderTemplate();
|
|
@@ -135,7 +137,7 @@ export declare class HistogramDateRange extends LitElement {
|
|
|
135
137
|
get tooltipTemplate(): TemplateResult;
|
|
136
138
|
private get noDataTemplate();
|
|
137
139
|
private get activityIndicatorTemplate();
|
|
138
|
-
static styles: import("lit").
|
|
140
|
+
static styles: import("lit").CSSResult;
|
|
139
141
|
render(): TemplateResult;
|
|
140
142
|
}
|
|
141
143
|
declare global {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
-
import { css, html, LitElement, svg, } from 'lit';
|
|
2
|
+
import { css, html, nothing, LitElement, svg, } from 'lit';
|
|
3
3
|
import { property, state, customElement } from 'lit/decorators.js';
|
|
4
4
|
import { live } from 'lit/directives/live.js';
|
|
5
5
|
import dayjs from 'dayjs/esm/index.js';
|
|
6
|
+
import customParseFormat from 'dayjs/esm/plugin/customParseFormat';
|
|
7
|
+
dayjs.extend(customParseFormat);
|
|
6
8
|
import '@internetarchive/ia-activity-indicator/ia-activity-indicator';
|
|
7
9
|
// these values can be overridden via the component's HTML (camelCased) attributes
|
|
8
10
|
const WIDTH = 180;
|
|
@@ -12,21 +14,23 @@ const TOOLTIP_WIDTH = 125;
|
|
|
12
14
|
const TOOLTIP_HEIGHT = 30;
|
|
13
15
|
const DATE_FORMAT = 'YYYY';
|
|
14
16
|
const MISSING_DATA = 'no data';
|
|
15
|
-
const UPDATE_DEBOUNCE_DELAY_MS =
|
|
17
|
+
const UPDATE_DEBOUNCE_DELAY_MS = 0;
|
|
16
18
|
// this constant is not set up to be overridden
|
|
17
19
|
const SLIDER_CORNER_SIZE = 4;
|
|
18
20
|
// these CSS custom props can be overridden from the HTML that is invoking this component
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
+
const sliderColor = css `var(--histogramDateRangeSliderColor, #4B65FE)`;
|
|
22
|
+
const selectedRangeColor = css `var(--histogramDateRangeSelectedRangeColor, #DBE0FF)`;
|
|
21
23
|
const barIncludedFill = css `var(--histogramDateRangeBarIncludedFill, #2C2C2C)`;
|
|
22
24
|
const activityIndicatorColor = css `var(--histogramDateRangeActivityIndicator, #2C2C2C)`;
|
|
23
25
|
const barExcludedFill = css `var(--histogramDateRangeBarExcludedFill, #CCCCCC)`;
|
|
24
26
|
const inputBorder = css `var(--histogramDateRangeInputBorder, 0.5px solid #2C2C2C)`;
|
|
25
27
|
const inputWidth = css `var(--histogramDateRangeInputWidth, 35px)`;
|
|
26
28
|
const inputFontSize = css `var(--histogramDateRangeInputFontSize, 1.2rem)`;
|
|
29
|
+
const inputFontFamily = css `var(--histogramDateRangeInputFontFamily, sans-serif)`;
|
|
27
30
|
const tooltipBackgroundColor = css `var(--histogramDateRangeTooltipBackgroundColor, #2C2C2C)`;
|
|
28
31
|
const tooltipTextColor = css `var(--histogramDateRangeTooltipTextColor, #FFFFFF)`;
|
|
29
32
|
const tooltipFontSize = css `var(--histogramDateRangeTooltipFontSize, 1.1rem)`;
|
|
33
|
+
const tooltipFontFamily = css `var(--histogramDateRangeTooltipFontFamily, sans-serif)`;
|
|
30
34
|
let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
31
35
|
constructor() {
|
|
32
36
|
/* eslint-disable lines-between-class-members */
|
|
@@ -89,12 +93,11 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
89
93
|
this.move = (e) => {
|
|
90
94
|
const newX = e.offsetX - this._dragOffset;
|
|
91
95
|
const slider = this._currentSlider;
|
|
92
|
-
const date = this.translatePositionToDate(newX);
|
|
93
96
|
if (slider.id === 'slider-min') {
|
|
94
|
-
this.minSelectedDate =
|
|
97
|
+
this.minSelectedDate = this.translatePositionToDate(this.validMinSliderX(newX));
|
|
95
98
|
}
|
|
96
99
|
else {
|
|
97
|
-
this.maxSelectedDate =
|
|
100
|
+
this.maxSelectedDate = this.translatePositionToDate(this.validMaxSliderX(newX));
|
|
98
101
|
}
|
|
99
102
|
};
|
|
100
103
|
}
|
|
@@ -104,7 +107,12 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
104
107
|
super.disconnectedCallback();
|
|
105
108
|
}
|
|
106
109
|
updated(changedProps) {
|
|
107
|
-
|
|
110
|
+
// check for changes that would affect bin data calculations
|
|
111
|
+
if (changedProps.has('bins') ||
|
|
112
|
+
changedProps.has('minDate') ||
|
|
113
|
+
changedProps.has('maxDate') ||
|
|
114
|
+
changedProps.has('minSelectedDate') ||
|
|
115
|
+
changedProps.has('maxSelectedDate')) {
|
|
108
116
|
this.handleDataUpdate();
|
|
109
117
|
}
|
|
110
118
|
}
|
|
@@ -120,8 +128,8 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
120
128
|
return;
|
|
121
129
|
}
|
|
122
130
|
this._histWidth = this.width - this.sliderWidth * 2;
|
|
123
|
-
this._minDateMS =
|
|
124
|
-
this._maxDateMS =
|
|
131
|
+
this._minDateMS = this.getMSFromString(this.minDate);
|
|
132
|
+
this._maxDateMS = this.getMSFromString(this.maxDate);
|
|
125
133
|
this._binWidth = this._histWidth / this._numBins;
|
|
126
134
|
this._previousDateRange = this.currentDateRangeString;
|
|
127
135
|
this._histData = this.calculateHistData();
|
|
@@ -136,11 +144,16 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
136
144
|
calculateHistData() {
|
|
137
145
|
const minValue = Math.min(...this.bins);
|
|
138
146
|
const maxValue = Math.max(...this.bins);
|
|
139
|
-
|
|
147
|
+
// if there is no difference between the min and max values, use a range of
|
|
148
|
+
// 1 because log scaling will fail if the range is 0
|
|
149
|
+
const valueRange = minValue === maxValue ? 1 : Math.log1p(maxValue - minValue);
|
|
150
|
+
const valueScale = this.height / valueRange;
|
|
140
151
|
const dateScale = this.dateRangeMS / this._numBins;
|
|
141
152
|
return this.bins.map((v, i) => {
|
|
142
153
|
return {
|
|
143
154
|
value: v,
|
|
155
|
+
// use log scaling for the height of the bar to prevent tall bars from
|
|
156
|
+
// making the smaller ones too small to see
|
|
144
157
|
height: Math.floor(Math.log1p(v) * valueScale),
|
|
145
158
|
binStart: `${this.formatDate(i * dateScale + this._minDateMS)}`,
|
|
146
159
|
binEnd: `${this.formatDate((i + 1) * dateScale + this._minDateMS)}`,
|
|
@@ -166,51 +179,55 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
166
179
|
}
|
|
167
180
|
/** formatted minimum date of selected date range */
|
|
168
181
|
get minSelectedDate() {
|
|
169
|
-
return this.formatDate(this._minSelectedDate);
|
|
182
|
+
return this.formatDate(this.getMSFromString(this._minSelectedDate));
|
|
170
183
|
}
|
|
184
|
+
/** updates minSelectedDate if new date is valid */
|
|
171
185
|
set minSelectedDate(rawDate) {
|
|
172
186
|
if (!this._minSelectedDate) {
|
|
173
187
|
// because the values needed to calculate valid max/min values are not
|
|
174
188
|
// available during the lit init when it's populating properties from
|
|
175
189
|
// attributes, fall back to just the raw date if nothing is already set
|
|
176
190
|
this._minSelectedDate = rawDate;
|
|
191
|
+
return;
|
|
177
192
|
}
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
|
|
181
|
-
this._minSelectedDate = this.
|
|
193
|
+
let ms = this.getMSFromString(rawDate);
|
|
194
|
+
if (!Number.isNaN(ms)) {
|
|
195
|
+
ms = Math.min(ms, this.getMSFromString(this._maxSelectedDate));
|
|
196
|
+
this._minSelectedDate = this.formatDate(ms);
|
|
182
197
|
}
|
|
183
198
|
this.requestUpdate();
|
|
184
199
|
}
|
|
185
200
|
/** formatted maximum date of selected date range */
|
|
186
201
|
get maxSelectedDate() {
|
|
187
|
-
return this.formatDate(this._maxSelectedDate);
|
|
202
|
+
return this.formatDate(this.getMSFromString(this._maxSelectedDate));
|
|
188
203
|
}
|
|
204
|
+
/** updates maxSelectedDate if new date is valid */
|
|
189
205
|
set maxSelectedDate(rawDate) {
|
|
190
206
|
if (!this._maxSelectedDate) {
|
|
191
|
-
//
|
|
207
|
+
// because the values needed to calculate valid max/min values are not
|
|
208
|
+
// available during the lit init when it's populating properties from
|
|
209
|
+
// attributes, fall back to just the raw date if nothing is already set
|
|
192
210
|
this._maxSelectedDate = rawDate;
|
|
211
|
+
return;
|
|
193
212
|
}
|
|
194
|
-
|
|
195
|
-
if (
|
|
196
|
-
|
|
197
|
-
this._maxSelectedDate = this.
|
|
213
|
+
let ms = this.getMSFromString(rawDate);
|
|
214
|
+
if (!Number.isNaN(ms)) {
|
|
215
|
+
ms = Math.max(this.getMSFromString(this._minSelectedDate), ms);
|
|
216
|
+
this._maxSelectedDate = this.formatDate(ms);
|
|
198
217
|
}
|
|
199
218
|
this.requestUpdate();
|
|
200
219
|
}
|
|
201
220
|
/** horizontal position of min date slider */
|
|
202
221
|
get minSliderX() {
|
|
203
|
-
var _a;
|
|
204
|
-
return (
|
|
205
222
|
// default to leftmost position if missing or invalid min position
|
|
206
|
-
|
|
223
|
+
const x = this.translateDateToPosition(this.minSelectedDate);
|
|
224
|
+
return this.validMinSliderX(x);
|
|
207
225
|
}
|
|
208
226
|
/** horizontal position of max date slider */
|
|
209
227
|
get maxSliderX() {
|
|
210
|
-
var _a;
|
|
211
|
-
return (
|
|
212
228
|
// default to rightmost position if missing or invalid max position
|
|
213
|
-
|
|
229
|
+
const x = this.translateDateToPosition(this.maxSelectedDate);
|
|
230
|
+
return this.validMaxSliderX(x);
|
|
214
231
|
}
|
|
215
232
|
get dateRangeMS() {
|
|
216
233
|
return this._maxDateMS - this._minDateMS;
|
|
@@ -223,10 +240,11 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
223
240
|
const x = target.x.baseVal.value + this.sliderWidth / 2;
|
|
224
241
|
const dataset = target.dataset;
|
|
225
242
|
const itemsText = `item${dataset.numItems !== '1' ? 's' : ''}`;
|
|
243
|
+
const formattedNumItems = Number(dataset.numItems).toLocaleString();
|
|
226
244
|
this._tooltipOffset =
|
|
227
245
|
x + (this._binWidth - this.sliderWidth - this.tooltipWidth) / 2;
|
|
228
246
|
this._tooltipContent = html `
|
|
229
|
-
${
|
|
247
|
+
${formattedNumItems} ${itemsText}<br />
|
|
230
248
|
${dataset.binStart} - ${dataset.binEnd}
|
|
231
249
|
`;
|
|
232
250
|
this._tooltipVisible = true;
|
|
@@ -244,8 +262,10 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
244
262
|
* to the position of the max slider
|
|
245
263
|
*/
|
|
246
264
|
validMinSliderX(newX) {
|
|
247
|
-
|
|
248
|
-
|
|
265
|
+
if (Number.isNaN(newX)) {
|
|
266
|
+
return this.sliderWidth;
|
|
267
|
+
}
|
|
268
|
+
return this.clamp(newX, this.sliderWidth, this.translateDateToPosition(this.maxSelectedDate));
|
|
249
269
|
}
|
|
250
270
|
/**
|
|
251
271
|
* Constrain a proposed value for the maximum (right) slider
|
|
@@ -256,8 +276,10 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
256
276
|
* then set it to the position of the min slider
|
|
257
277
|
*/
|
|
258
278
|
validMaxSliderX(newX) {
|
|
259
|
-
|
|
260
|
-
|
|
279
|
+
if (Number.isNaN(newX)) {
|
|
280
|
+
return this.width - this.sliderWidth;
|
|
281
|
+
}
|
|
282
|
+
return this.clamp(newX, this.translateDateToPosition(this.minSelectedDate), this.width - this.sliderWidth);
|
|
261
283
|
}
|
|
262
284
|
addListeners() {
|
|
263
285
|
window.addEventListener('pointermove', this.move);
|
|
@@ -334,10 +356,13 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
334
356
|
* @returns x-position of slider
|
|
335
357
|
*/
|
|
336
358
|
translateDateToPosition(date) {
|
|
337
|
-
const milliseconds =
|
|
338
|
-
|
|
339
|
-
((milliseconds - this._minDateMS) * this._histWidth) / this.dateRangeMS;
|
|
340
|
-
|
|
359
|
+
const milliseconds = this.getMSFromString(date);
|
|
360
|
+
return (this.sliderWidth +
|
|
361
|
+
((milliseconds - this._minDateMS) * this._histWidth) / this.dateRangeMS);
|
|
362
|
+
}
|
|
363
|
+
/** ensure that the returned value is between minValue and maxValue */
|
|
364
|
+
clamp(x, minValue, maxValue) {
|
|
365
|
+
return Math.min(Math.max(x, minValue), maxValue);
|
|
341
366
|
}
|
|
342
367
|
handleMinDateInput(e) {
|
|
343
368
|
const target = e.currentTarget;
|
|
@@ -349,27 +374,37 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
349
374
|
this.maxSelectedDate = target.value;
|
|
350
375
|
this.beginEmitUpdateProcess();
|
|
351
376
|
}
|
|
377
|
+
handleKeyUp(e) {
|
|
378
|
+
if (e.key === 'Enter') {
|
|
379
|
+
const target = e.currentTarget;
|
|
380
|
+
target.blur();
|
|
381
|
+
}
|
|
382
|
+
}
|
|
352
383
|
get currentDateRangeString() {
|
|
353
384
|
return `${this.minSelectedDate}:${this.maxSelectedDate}`;
|
|
354
385
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
386
|
+
getMSFromString(date) {
|
|
387
|
+
const digitGroupCount = (date.split(/(\d+)/).length - 1) / 2;
|
|
388
|
+
if (digitGroupCount === 1) {
|
|
389
|
+
// if there's just a single set of digits, assume it's a year
|
|
390
|
+
const dateObj = new Date(0, 0); // start at January 1, 1900
|
|
391
|
+
dateObj.setFullYear(Number(date)); // override year (=> 0099-01-01) = 99 CE
|
|
392
|
+
return dateObj.getTime(); // get time in milliseconds
|
|
393
|
+
}
|
|
394
|
+
return dayjs(date, [this.dateFormat, DATE_FORMAT]).valueOf();
|
|
362
395
|
}
|
|
363
396
|
handleBarClick(e) {
|
|
364
|
-
var _a, _b;
|
|
365
397
|
const dataset = e.currentTarget.dataset;
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
398
|
+
const distanceFromMinSlider = this.getMSFromString(dataset.binStart) -
|
|
399
|
+
this.getMSFromString(this.minSelectedDate);
|
|
400
|
+
const distanceFromMaxSlider = this.getMSFromString(this.maxSelectedDate) -
|
|
401
|
+
this.getMSFromString(dataset.binEnd);
|
|
402
|
+
// update the selection by moving the nearer slider
|
|
403
|
+
if (distanceFromMinSlider < distanceFromMaxSlider) {
|
|
404
|
+
this.minSelectedDate = dataset.binStart;
|
|
369
405
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
this.maxSelectedDate = (_b = dataset.binEnd) !== null && _b !== void 0 ? _b : '';
|
|
406
|
+
else {
|
|
407
|
+
this.maxSelectedDate = dataset.binEnd;
|
|
373
408
|
}
|
|
374
409
|
this.beginEmitUpdateProcess();
|
|
375
410
|
}
|
|
@@ -407,9 +442,12 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
407
442
|
return svg `
|
|
408
443
|
<svg
|
|
409
444
|
id="${id}"
|
|
445
|
+
class="
|
|
446
|
+
${this.disabled ? '' : 'draggable'}
|
|
447
|
+
${this._isDragging ? 'dragging' : ''}"
|
|
410
448
|
@pointerdown="${this.drag}"
|
|
411
449
|
>
|
|
412
|
-
<path d="${sliderShape} z" fill="${
|
|
450
|
+
<path d="${sliderShape} z" fill="${sliderColor}" />
|
|
413
451
|
<rect
|
|
414
452
|
x="${sliderPositionX - this.sliderWidth * k + this.sliderWidth * 0.4 * k}"
|
|
415
453
|
y="${this.height / 3}"
|
|
@@ -434,7 +472,7 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
434
472
|
y="0"
|
|
435
473
|
width="${this.maxSliderX - this.minSliderX}"
|
|
436
474
|
height="${this.height}"
|
|
437
|
-
fill="${
|
|
475
|
+
fill="${selectedRangeColor}"
|
|
438
476
|
/>`;
|
|
439
477
|
}
|
|
440
478
|
get histogramTemplate() {
|
|
@@ -457,7 +495,7 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
457
495
|
@pointerenter="${this.showTooltip}"
|
|
458
496
|
@pointerleave="${this.hideTooltip}"
|
|
459
497
|
@click="${this.handleBarClick}"
|
|
460
|
-
fill="${x >= this.minSliderX && x <= this.maxSliderX
|
|
498
|
+
fill="${x + barWidth >= this.minSliderX && x <= this.maxSliderX
|
|
461
499
|
? barIncludedFill
|
|
462
500
|
: barExcludedFill}"
|
|
463
501
|
data-num-items="${data.value}"
|
|
@@ -468,9 +506,17 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
468
506
|
return bar;
|
|
469
507
|
});
|
|
470
508
|
}
|
|
471
|
-
formatDate(
|
|
472
|
-
|
|
473
|
-
|
|
509
|
+
formatDate(dateMS) {
|
|
510
|
+
if (Number.isNaN(dateMS)) {
|
|
511
|
+
return '';
|
|
512
|
+
}
|
|
513
|
+
const date = dayjs(dateMS);
|
|
514
|
+
if (date.year() < 1000) {
|
|
515
|
+
// years before 1000 don't play well with dayjs custom formatting, so fall
|
|
516
|
+
// back to displaying only the year
|
|
517
|
+
return String(date.year());
|
|
518
|
+
}
|
|
519
|
+
return date.format(this.dateFormat);
|
|
474
520
|
}
|
|
475
521
|
/**
|
|
476
522
|
* NOTE: we are relying on the lit `live` directive in the template to
|
|
@@ -486,6 +532,7 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
486
532
|
type="text"
|
|
487
533
|
@focus="${this.cancelPendingUpdateEvent}"
|
|
488
534
|
@blur="${this.handleMinDateInput}"
|
|
535
|
+
@keyup="${this.handleKeyUp}"
|
|
489
536
|
.value="${live(this.minSelectedDate)}"
|
|
490
537
|
?disabled="${this.disabled}"
|
|
491
538
|
/>
|
|
@@ -499,6 +546,7 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
499
546
|
type="text"
|
|
500
547
|
@focus="${this.cancelPendingUpdateEvent}"
|
|
501
548
|
@blur="${this.handleMaxDateInput}"
|
|
549
|
+
@keyup="${this.handleKeyUp}"
|
|
502
550
|
.value="${live(this.maxSelectedDate)}"
|
|
503
551
|
?disabled="${this.disabled}"
|
|
504
552
|
/>
|
|
@@ -528,7 +576,7 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
|
|
|
528
576
|
}
|
|
529
577
|
get activityIndicatorTemplate() {
|
|
530
578
|
if (!this.loading) {
|
|
531
|
-
return
|
|
579
|
+
return nothing;
|
|
532
580
|
}
|
|
533
581
|
return html `
|
|
534
582
|
<ia-activity-indicator mode="processing"> </ia-activity-indicator>
|
|
@@ -608,11 +656,17 @@ HistogramDateRange.styles = css `
|
|
|
608
656
|
clicks on the bars, preventing users from being able to click in between
|
|
609
657
|
bars */
|
|
610
658
|
stroke: rgba(0, 0, 0, 0);
|
|
659
|
+
/* ensure transparent stroke wide enough to cover gap between bars */
|
|
611
660
|
stroke-width: 2px;
|
|
612
661
|
}
|
|
613
662
|
.bar:hover {
|
|
663
|
+
/* highlight currently hovered bar */
|
|
614
664
|
fill-opacity: 0.7;
|
|
615
665
|
}
|
|
666
|
+
.disabled .bar:hover {
|
|
667
|
+
/* ensure no visual hover interaction when disabled */
|
|
668
|
+
fill-opacity: 1;
|
|
669
|
+
}
|
|
616
670
|
/****** histogram ********/
|
|
617
671
|
#tooltip {
|
|
618
672
|
position: absolute;
|
|
@@ -622,7 +676,7 @@ HistogramDateRange.styles = css `
|
|
|
622
676
|
border-radius: 3px;
|
|
623
677
|
padding: 2px;
|
|
624
678
|
font-size: ${tooltipFontSize};
|
|
625
|
-
font-family:
|
|
679
|
+
font-family: ${tooltipFontFamily};
|
|
626
680
|
touch-action: none;
|
|
627
681
|
pointer-events: none;
|
|
628
682
|
}
|
|
@@ -659,6 +713,7 @@ HistogramDateRange.styles = css `
|
|
|
659
713
|
border-radius: 2px !important;
|
|
660
714
|
text-align: center;
|
|
661
715
|
font-size: ${inputFontSize};
|
|
716
|
+
font-family: ${inputFontFamily};
|
|
662
717
|
}
|
|
663
718
|
`;
|
|
664
719
|
__decorate([
|