@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 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
- <style>
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
- '\n' + JSON.stringify(e.detail);
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">pre-selected range with default date format</div>
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">default range with custom date format</div>
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 1, 1972"
72
- maxDate="12/21/1980"
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; no debounce delay</div>
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 an array like [0, 1, 2, ... 49]
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
- bins=""
124
- missingDataMessage="no data..."
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
- /** minimum selected date in milliseconds */
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").CSSResultGroup;
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 = 1000;
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 sliderFill = css `var(--histogramDateRangeSliderFill, #4B65FE)`;
20
- const selectedRangeFill = css `var(--histogramDateRangeSelectedRangeFill, #DBE0FF)`;
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 = date;
97
+ this.minSelectedDate = this.translatePositionToDate(this.validMinSliderX(newX));
95
98
  }
96
99
  else {
97
- this.maxSelectedDate = date;
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
- if (changedProps.has('bins') || changedProps.has('Date')) {
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 = dayjs(this.minDate).valueOf();
124
- this._maxDateMS = dayjs(this.maxDate).valueOf();
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
- const valueScale = this.height / Math.log1p(maxValue - minValue);
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
- const x = this.translateDateToPosition(rawDate);
179
- if (x) {
180
- const validX = this.validMinSliderX(x);
181
- this._minSelectedDate = this.translatePositionToDate(validX);
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
- // see comment above in the minSelectedDate setter
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
- const x = this.translateDateToPosition(rawDate);
195
- if (x) {
196
- const validX = this.validMaxSliderX(x);
197
- this._maxSelectedDate = this.translatePositionToDate(validX);
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
- (_a = this.translateDateToPosition(this.minSelectedDate)) !== null && _a !== void 0 ? _a : this.sliderWidth);
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
- (_a = this.translateDateToPosition(this.maxSelectedDate)) !== null && _a !== void 0 ? _a : this.width - this.sliderWidth);
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
- ${dataset.numItems} ${itemsText}<br />
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
- const validX = Math.max(newX, this.sliderWidth);
248
- return Math.min(validX, this.maxSliderX);
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
- const validX = Math.max(newX, this.minSliderX);
260
- return Math.min(validX, this.width - this.sliderWidth);
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 = dayjs(date).valueOf();
338
- const xPosition = this.sliderWidth +
339
- ((milliseconds - this._minDateMS) * this._histWidth) / this.dateRangeMS;
340
- return isNaN(milliseconds) || isNaN(xPosition) ? null : xPosition;
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
- /** minimum selected date in milliseconds */
356
- get minSelectedDateMS() {
357
- return dayjs(this.minSelectedDate).valueOf();
358
- }
359
- /** maximum selected date in milliseconds */
360
- get maxSelectedDateMS() {
361
- return dayjs(this.maxSelectedDate).valueOf();
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 binStartDateMS = dayjs(dataset.binStart).valueOf();
367
- if (binStartDateMS < this.minSelectedDateMS) {
368
- this.minSelectedDate = (_a = dataset.binStart) !== null && _a !== void 0 ? _a : '';
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
- const binEndDateMS = dayjs(dataset.binEnd).valueOf();
371
- if (binEndDateMS > this.maxSelectedDateMS) {
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="${sliderFill}" />
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="${selectedRangeFill}"
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(rawDate) {
472
- const date = dayjs(rawDate);
473
- return date.isValid() ? date.format(this.dateFormat) : '';
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 html ``;
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: sans-serif;
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([