@internetarchive/histogram-date-range 0.1.1-alpha → 0.1.4

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.html CHANGED
@@ -48,7 +48,24 @@
48
48
  ></histogram-date-range>
49
49
  </div>
50
50
 
51
-
51
+ <div class="container">
52
+ <div class="description">
53
+ small diff between max and min values
54
+ </div>
55
+ <histogram-date-range
56
+ width="175"
57
+ tooltipwidth="120"
58
+ dateformat="YYYY"
59
+ updatedelay="1000"
60
+ missingdatamessage="..."
61
+ minselecteddate="1987"
62
+ maxselecteddate="2016"
63
+ mindate="1987"
64
+ maxdate="2016"
65
+ bins="[1519,1643,1880,2046,1973,2085,2148,2152,2349,2304,2314,2484,2590,2450,2495,2475,2392,2631,2504,2619,2519,2552,2462,2217,2171,2132,2127,2041,1638,1441]"
66
+ >
67
+ </histogram-date-range>
68
+ </div>
52
69
 
53
70
  <div class="container">
54
71
  <div class="description">small year range and few bins</div>
@@ -120,7 +137,7 @@
120
137
  });
121
138
  </script>
122
139
 
123
- <!-- <div class="container">
140
+ <div class="container">
124
141
  <div class="description">
125
142
  single bin
126
143
  </div>
@@ -131,7 +148,7 @@
131
148
  <div class="container">
132
149
  <div class="description">empty data</div>
133
150
  <histogram-date-range missingDataMessage="no data..."></histoghistogram-date-range>
134
- </div> -->
151
+ </div>
135
152
 
136
153
  </body>
137
154
  </html>
@@ -42,6 +42,8 @@ export declare class HistogramDateRange extends LitElement {
42
42
  private calculateHistData;
43
43
  private get hasBinData();
44
44
  private get _numBins();
45
+ private get histogramLeftEdgeX();
46
+ private get histogramRightEdgeX();
45
47
  /** component's loading (and disabled) state */
46
48
  get loading(): boolean;
47
49
  set loading(value: boolean);
@@ -72,18 +74,18 @@ export declare class HistogramDateRange extends LitElement {
72
74
  * Constrain a proposed value for the minimum (left) slider
73
75
  *
74
76
  * If the value is less than the leftmost valid position, then set it to the
75
- * left edge of the widget (ie the slider width). If the value is greater than
76
- * the rightmost valid position (the position of the max slider), then set it
77
- * to the position of the max slider
77
+ * left edge of the histogram (ie the slider width). If the value is greater
78
+ * than the rightmost valid position (the position of the max slider), then
79
+ * set it to the position of the max slider
78
80
  */
79
81
  private validMinSliderX;
80
82
  /**
81
83
  * Constrain a proposed value for the maximum (right) slider
82
84
  *
83
85
  * If the value is greater than the rightmost valid position, then set it to
84
- * the right edge of the widget (ie widget width - slider width). If the value
85
- * is less than the leftmost valid position (the position of the min slider),
86
- * then set it to the position of the min slider
86
+ * the right edge of the histogram (ie histogram width - slider width). If the
87
+ * value is less than the leftmost valid position (the position of the min
88
+ * slider), then set it to the position of the min slider
87
89
  */
88
90
  private validMaxSliderX;
89
91
  private addListeners;
@@ -105,8 +107,7 @@ export declare class HistogramDateRange extends LitElement {
105
107
  */
106
108
  private translatePositionToDate;
107
109
  /**
108
- * Returns slider x-position corresponding to given date (or null if invalid
109
- * date)
110
+ * Returns slider x-position corresponding to given date
110
111
  *
111
112
  * @param date
112
113
  * @returns x-position of slider
@@ -119,6 +120,12 @@ export declare class HistogramDateRange extends LitElement {
119
120
  private handleKeyUp;
120
121
  private get currentDateRangeString();
121
122
  private getMSFromString;
123
+ /**
124
+ * expand or narrow the selected range by moving the slider nearest the
125
+ * clicked bar to the outer edge of the clicked bar
126
+ *
127
+ * @param e Event click event from a histogram bar
128
+ */
122
129
  private handleBarClick;
123
130
  private get minSliderTemplate();
124
131
  private get maxSliderTemplate();
@@ -146,7 +146,7 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
146
146
  const maxValue = Math.max(...this.bins);
147
147
  // if there is no difference between the min and max values, use a range of
148
148
  // 1 because log scaling will fail if the range is 0
149
- const valueRange = minValue === maxValue ? 1 : Math.log1p(maxValue - minValue);
149
+ const valueRange = minValue === maxValue ? 1 : Math.log1p(maxValue);
150
150
  const valueScale = this.height / valueRange;
151
151
  const dateScale = this.dateRangeMS / this._numBins;
152
152
  return this.bins.map((v, i) => {
@@ -169,6 +169,12 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
169
169
  }
170
170
  return this.bins.length;
171
171
  }
172
+ get histogramLeftEdgeX() {
173
+ return this.sliderWidth;
174
+ }
175
+ get histogramRightEdgeX() {
176
+ return this.width - this.sliderWidth;
177
+ }
172
178
  /** component's loading (and disabled) state */
173
179
  get loading() {
174
180
  return this._isLoading;
@@ -190,10 +196,11 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
190
196
  this._minSelectedDate = rawDate;
191
197
  return;
192
198
  }
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);
199
+ const proposedDateMS = this.getMSFromString(rawDate);
200
+ const isValidDate = !Number.isNaN(proposedDateMS);
201
+ const isNotTooRecent = proposedDateMS <= this.getMSFromString(this.maxSelectedDate);
202
+ if (isValidDate && isNotTooRecent) {
203
+ this._minSelectedDate = this.formatDate(proposedDateMS);
197
204
  }
198
205
  this.requestUpdate();
199
206
  }
@@ -210,22 +217,21 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
210
217
  this._maxSelectedDate = rawDate;
211
218
  return;
212
219
  }
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);
220
+ const proposedDateMS = this.getMSFromString(rawDate);
221
+ const isValidDate = !Number.isNaN(proposedDateMS);
222
+ const isNotTooOld = proposedDateMS >= this.getMSFromString(this.minSelectedDate);
223
+ if (isValidDate && isNotTooOld) {
224
+ this._maxSelectedDate = this.formatDate(proposedDateMS);
217
225
  }
218
226
  this.requestUpdate();
219
227
  }
220
228
  /** horizontal position of min date slider */
221
229
  get minSliderX() {
222
- // default to leftmost position if missing or invalid min position
223
230
  const x = this.translateDateToPosition(this.minSelectedDate);
224
231
  return this.validMinSliderX(x);
225
232
  }
226
233
  /** horizontal position of max date slider */
227
234
  get maxSliderX() {
228
- // default to rightmost position if missing or invalid max position
229
235
  const x = this.translateDateToPosition(this.maxSelectedDate);
230
236
  return this.validMaxSliderX(x);
231
237
  }
@@ -257,29 +263,33 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
257
263
  * Constrain a proposed value for the minimum (left) slider
258
264
  *
259
265
  * If the value is less than the leftmost valid position, then set it to the
260
- * left edge of the widget (ie the slider width). If the value is greater than
261
- * the rightmost valid position (the position of the max slider), then set it
262
- * to the position of the max slider
266
+ * left edge of the histogram (ie the slider width). If the value is greater
267
+ * than the rightmost valid position (the position of the max slider), then
268
+ * set it to the position of the max slider
263
269
  */
264
270
  validMinSliderX(newX) {
265
- if (Number.isNaN(newX)) {
266
- return this.sliderWidth;
267
- }
268
- return this.clamp(newX, this.sliderWidth, this.translateDateToPosition(this.maxSelectedDate));
271
+ // allow the left slider to go right only to the right slider, even if the
272
+ // max selected date is out of range
273
+ const rightLimit = Math.min(this.translateDateToPosition(this.maxSelectedDate), this.histogramRightEdgeX);
274
+ newX = this.clamp(newX, this.histogramLeftEdgeX, rightLimit);
275
+ const isInvalid = Number.isNaN(newX) || rightLimit < this.histogramLeftEdgeX;
276
+ return isInvalid ? this.histogramLeftEdgeX : newX;
269
277
  }
270
278
  /**
271
279
  * Constrain a proposed value for the maximum (right) slider
272
280
  *
273
281
  * If the value is greater than the rightmost valid position, then set it to
274
- * the right edge of the widget (ie widget width - slider width). If the value
275
- * is less than the leftmost valid position (the position of the min slider),
276
- * then set it to the position of the min slider
282
+ * the right edge of the histogram (ie histogram width - slider width). If the
283
+ * value is less than the leftmost valid position (the position of the min
284
+ * slider), then set it to the position of the min slider
277
285
  */
278
286
  validMaxSliderX(newX) {
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);
287
+ // allow the right slider to go left only to the left slider, even if the
288
+ // min selected date is out of range
289
+ const leftLimit = Math.max(this.histogramLeftEdgeX, this.translateDateToPosition(this.minSelectedDate));
290
+ newX = this.clamp(newX, leftLimit, this.histogramRightEdgeX);
291
+ const isInvalid = Number.isNaN(newX) || leftLimit > this.histogramRightEdgeX;
292
+ return isInvalid ? this.histogramRightEdgeX : newX;
283
293
  }
284
294
  addListeners() {
285
295
  window.addEventListener('pointermove', this.move);
@@ -349,8 +359,7 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
349
359
  return this.formatDate(this._minDateMS + milliseconds);
350
360
  }
351
361
  /**
352
- * Returns slider x-position corresponding to given date (or null if invalid
353
- * date)
362
+ * Returns slider x-position corresponding to given date
354
363
  *
355
364
  * @param date
356
365
  * @returns x-position of slider
@@ -378,6 +387,12 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
378
387
  if (e.key === 'Enter') {
379
388
  const target = e.currentTarget;
380
389
  target.blur();
390
+ if (target.id === 'date-min') {
391
+ this.handleMinDateInput(e);
392
+ }
393
+ else if (target.id === 'date-max') {
394
+ this.handleMaxDateInput(e);
395
+ }
381
396
  }
382
397
  }
383
398
  get currentDateRangeString() {
@@ -388,18 +403,27 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
388
403
  if (digitGroupCount === 1) {
389
404
  // if there's just a single set of digits, assume it's a year
390
405
  const dateObj = new Date(0, 0); // start at January 1, 1900
391
- dateObj.setFullYear(Number(date)); // override year (=> 0099-01-01) = 99 CE
406
+ dateObj.setFullYear(Number(date)); // override year
392
407
  return dateObj.getTime(); // get time in milliseconds
393
408
  }
394
409
  return dayjs(date, [this.dateFormat, DATE_FORMAT]).valueOf();
395
410
  }
411
+ /**
412
+ * expand or narrow the selected range by moving the slider nearest the
413
+ * clicked bar to the outer edge of the clicked bar
414
+ *
415
+ * @param e Event click event from a histogram bar
416
+ */
396
417
  handleBarClick(e) {
397
418
  const dataset = e.currentTarget.dataset;
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
419
+ // use the midpoint of the width of the clicked bar to determine which is
420
+ // the nearest slider
421
+ const clickPosition = (this.getMSFromString(dataset.binStart) +
422
+ this.getMSFromString(dataset.binEnd)) /
423
+ 2;
424
+ const distanceFromMinSlider = Math.abs(clickPosition - this.getMSFromString(this.minSelectedDate));
425
+ const distanceFromMaxSlider = Math.abs(clickPosition - this.getMSFromString(this.maxSelectedDate));
426
+ // update the selected range by moving the nearer slider
403
427
  if (distanceFromMinSlider < distanceFromMaxSlider) {
404
428
  this.minSelectedDate = dataset.binStart;
405
429
  }
@@ -1 +1 @@
1
- {"version":3,"file":"histogram-date-range.js","sourceRoot":"","sources":["../../src/histogram-date-range.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n nothing,\n LitElement,\n PropertyValues,\n svg,\n SVGTemplateResult,\n TemplateResult,\n} from 'lit';\nimport { property, state, customElement } from 'lit/decorators.js';\nimport { live } from 'lit/directives/live.js';\nimport dayjs from 'dayjs/esm/index.js';\nimport customParseFormat from 'dayjs/esm/plugin/customParseFormat';\ndayjs.extend(customParseFormat);\nimport '@internetarchive/ia-activity-indicator/ia-activity-indicator';\n\n// these values can be overridden via the component's HTML (camelCased) attributes\nconst WIDTH = 180;\nconst HEIGHT = 40;\nconst SLIDER_WIDTH = 10;\nconst TOOLTIP_WIDTH = 125;\nconst TOOLTIP_HEIGHT = 30;\nconst DATE_FORMAT = 'YYYY';\nconst MISSING_DATA = 'no data';\nconst UPDATE_DEBOUNCE_DELAY_MS = 0;\n\n// this constant is not set up to be overridden\nconst SLIDER_CORNER_SIZE = 4;\n\n// these CSS custom props can be overridden from the HTML that is invoking this component\nconst sliderColor = css`var(--histogramDateRangeSliderColor, #4B65FE)`;\nconst selectedRangeColor = css`var(--histogramDateRangeSelectedRangeColor, #DBE0FF)`;\nconst barIncludedFill = css`var(--histogramDateRangeBarIncludedFill, #2C2C2C)`;\nconst activityIndicatorColor = css`var(--histogramDateRangeActivityIndicator, #2C2C2C)`;\nconst barExcludedFill = css`var(--histogramDateRangeBarExcludedFill, #CCCCCC)`;\nconst inputBorder = css`var(--histogramDateRangeInputBorder, 0.5px solid #2C2C2C)`;\nconst inputWidth = css`var(--histogramDateRangeInputWidth, 35px)`;\nconst inputFontSize = css`var(--histogramDateRangeInputFontSize, 1.2rem)`;\nconst inputFontFamily = css`var(--histogramDateRangeInputFontFamily, sans-serif)`;\nconst tooltipBackgroundColor = css`var(--histogramDateRangeTooltipBackgroundColor, #2C2C2C)`;\nconst tooltipTextColor = css`var(--histogramDateRangeTooltipTextColor, #FFFFFF)`;\nconst tooltipFontSize = css`var(--histogramDateRangeTooltipFontSize, 1.1rem)`;\nconst tooltipFontFamily = css`var(--histogramDateRangeTooltipFontFamily, sans-serif)`;\n\ntype SliderId = 'slider-min' | 'slider-max';\n\ninterface HistogramItem {\n value: number;\n height: number;\n binStart: string;\n binEnd: string;\n}\n\ninterface BarDataset extends DOMStringMap {\n numItems: string;\n binStart: string;\n binEnd: string;\n}\n\n@customElement('histogram-date-range')\nexport class HistogramDateRange extends LitElement {\n /* eslint-disable lines-between-class-members */\n\n // public reactive properties that can be set via HTML attributes\n @property({ type: Number }) width = WIDTH;\n @property({ type: Number }) height = HEIGHT;\n @property({ type: Number }) sliderWidth = SLIDER_WIDTH;\n @property({ type: Number }) tooltipWidth = TOOLTIP_WIDTH;\n @property({ type: Number }) tooltipHeight = TOOLTIP_HEIGHT;\n @property({ type: Number }) updateDelay = UPDATE_DEBOUNCE_DELAY_MS;\n @property() dateFormat = DATE_FORMAT;\n @property() missingDataMessage = MISSING_DATA;\n @property() minDate = '';\n @property() maxDate = '';\n @property({ type: Boolean }) disabled = false;\n @property({ type: Object }) bins: number[] = [];\n\n // internal reactive properties not exposed as attributes\n @state() private _tooltipOffset = 0;\n @state() private _tooltipContent?: TemplateResult;\n @state() private _tooltipVisible = false;\n @state() private _isDragging = false;\n @state() private _isLoading = false;\n\n // non-reactive properties (changes don't auto-trigger re-rendering)\n private _minSelectedDate = '';\n private _maxSelectedDate = '';\n private _minDateMS = 0;\n private _maxDateMS = 0;\n private _dragOffset = 0;\n private _histWidth = 0;\n private _binWidth = 0;\n private _currentSlider?: SVGRectElement;\n private _histData: HistogramItem[] = [];\n private _emitUpdatedEventTimer?: ReturnType<typeof setTimeout>;\n private _previousDateRange = '';\n\n /* eslint-enable lines-between-class-members */\n\n disconnectedCallback(): void {\n this.removeListeners();\n super.disconnectedCallback();\n }\n\n updated(changedProps: PropertyValues): void {\n // check for changes that would affect bin data calculations\n if (\n changedProps.has('bins') ||\n changedProps.has('minDate') ||\n changedProps.has('maxDate') ||\n changedProps.has('minSelectedDate') ||\n changedProps.has('maxSelectedDate')\n ) {\n this.handleDataUpdate();\n }\n }\n\n /**\n * Set private properties that depend on the attribute bin data\n *\n * We're caching these values and not using getters to avoid recalculating all\n * of the hist data every time the user drags a slider or hovers over a bar\n * creating a tooltip.\n */\n private handleDataUpdate(): void {\n if (!this.hasBinData) {\n return;\n }\n this._histWidth = this.width - this.sliderWidth * 2;\n this._minDateMS = this.getMSFromString(this.minDate);\n this._maxDateMS = this.getMSFromString(this.maxDate);\n this._binWidth = this._histWidth / this._numBins;\n this._previousDateRange = this.currentDateRangeString;\n this._histData = this.calculateHistData();\n this.minSelectedDate = this.minSelectedDate\n ? this.minSelectedDate\n : this.minDate;\n this.maxSelectedDate = this.maxSelectedDate\n ? this.maxSelectedDate\n : this.maxDate;\n this.requestUpdate();\n }\n\n private calculateHistData(): HistogramItem[] {\n const minValue = Math.min(...this.bins);\n const maxValue = Math.max(...this.bins);\n // if there is no difference between the min and max values, use a range of\n // 1 because log scaling will fail if the range is 0\n const valueRange =\n minValue === maxValue ? 1 : Math.log1p(maxValue - minValue);\n const valueScale = this.height / valueRange;\n const dateScale = this.dateRangeMS / this._numBins;\n return this.bins.map((v: number, i: number) => {\n return {\n value: v,\n // use log scaling for the height of the bar to prevent tall bars from\n // making the smaller ones too small to see\n height: Math.floor(Math.log1p(v) * valueScale),\n binStart: `${this.formatDate(i * dateScale + this._minDateMS)}`,\n binEnd: `${this.formatDate((i + 1) * dateScale + this._minDateMS)}`,\n };\n });\n }\n\n private get hasBinData(): boolean {\n return this._numBins > 0;\n }\n\n private get _numBins(): number {\n if (!this.bins || !this.bins.length) {\n return 0;\n }\n return this.bins.length;\n }\n\n /** component's loading (and disabled) state */\n @property({ type: Boolean }) get loading(): boolean {\n return this._isLoading;\n }\n\n set loading(value: boolean) {\n this.disabled = value;\n this._isLoading = value;\n }\n\n /** formatted minimum date of selected date range */\n @property() get minSelectedDate(): string {\n return this.formatDate(this.getMSFromString(this._minSelectedDate));\n }\n\n /** updates minSelectedDate if new date is valid */\n set minSelectedDate(rawDate: string) {\n if (!this._minSelectedDate) {\n // because the values needed to calculate valid max/min values are not\n // available during the lit init when it's populating properties from\n // attributes, fall back to just the raw date if nothing is already set\n this._minSelectedDate = rawDate;\n return;\n }\n let ms = this.getMSFromString(rawDate);\n if (!Number.isNaN(ms)) {\n ms = Math.min(ms, this.getMSFromString(this._maxSelectedDate));\n this._minSelectedDate = this.formatDate(ms);\n }\n this.requestUpdate();\n }\n\n /** formatted maximum date of selected date range */\n @property() get maxSelectedDate(): string {\n return this.formatDate(this.getMSFromString(this._maxSelectedDate));\n }\n\n /** updates maxSelectedDate if new date is valid */\n set maxSelectedDate(rawDate: string) {\n if (!this._maxSelectedDate) {\n // because the values needed to calculate valid max/min values are not\n // available during the lit init when it's populating properties from\n // attributes, fall back to just the raw date if nothing is already set\n this._maxSelectedDate = rawDate;\n return;\n }\n let ms = this.getMSFromString(rawDate);\n if (!Number.isNaN(ms)) {\n ms = Math.max(this.getMSFromString(this._minSelectedDate), ms);\n this._maxSelectedDate = this.formatDate(ms);\n }\n this.requestUpdate();\n }\n\n /** horizontal position of min date slider */\n get minSliderX(): number {\n // default to leftmost position if missing or invalid min position\n const x = this.translateDateToPosition(this.minSelectedDate);\n return this.validMinSliderX(x);\n }\n\n /** horizontal position of max date slider */\n get maxSliderX(): number {\n // default to rightmost position if missing or invalid max position\n const x = this.translateDateToPosition(this.maxSelectedDate);\n return this.validMaxSliderX(x);\n }\n\n private get dateRangeMS(): number {\n return this._maxDateMS - this._minDateMS;\n }\n\n private showTooltip(e: PointerEvent): void {\n if (this._isDragging || this.disabled) {\n return;\n }\n const target = e.currentTarget as SVGRectElement;\n const x = target.x.baseVal.value + this.sliderWidth / 2;\n const dataset = target.dataset as BarDataset;\n const itemsText = `item${dataset.numItems !== '1' ? 's' : ''}`;\n const formattedNumItems = Number(dataset.numItems).toLocaleString();\n\n this._tooltipOffset =\n x + (this._binWidth - this.sliderWidth - this.tooltipWidth) / 2;\n\n this._tooltipContent = html`\n ${formattedNumItems} ${itemsText}<br />\n ${dataset.binStart} - ${dataset.binEnd}\n `;\n this._tooltipVisible = true;\n }\n\n private hideTooltip(): void {\n this._tooltipContent = undefined;\n this._tooltipVisible = false;\n }\n\n // use arrow functions (rather than standard JS class instance methods) so\n // that `this` is bound to the histogramDateRange object and not the event\n // target. for more info see\n // https://lit-element.polymer-project.org/guide/events#using-this-in-event-listeners\n private drag = (e: PointerEvent): void => {\n // prevent selecting text or other ranges while dragging, especially in Safari\n e.preventDefault();\n if (this.disabled) {\n return;\n }\n this.setDragOffset(e);\n this._isDragging = true;\n this.addListeners();\n this.cancelPendingUpdateEvent();\n };\n\n private drop = (): void => {\n if (this._isDragging) {\n this.removeListeners();\n this.beginEmitUpdateProcess();\n }\n this._isDragging = false;\n };\n\n /**\n * Adjust the date range based on slider movement\n *\n * @param e PointerEvent from the slider being moved\n */\n private move = (e: PointerEvent): void => {\n const newX = e.offsetX - this._dragOffset;\n const slider = this._currentSlider as SVGRectElement;\n if ((slider.id as SliderId) === 'slider-min') {\n this.minSelectedDate = this.translatePositionToDate(\n this.validMinSliderX(newX)\n );\n } else {\n this.maxSelectedDate = this.translatePositionToDate(\n this.validMaxSliderX(newX)\n );\n }\n };\n\n /**\n * Constrain a proposed value for the minimum (left) slider\n *\n * If the value is less than the leftmost valid position, then set it to the\n * left edge of the widget (ie the slider width). If the value is greater than\n * the rightmost valid position (the position of the max slider), then set it\n * to the position of the max slider\n */\n private validMinSliderX(newX: number): number {\n if (Number.isNaN(newX)) {\n return this.sliderWidth;\n }\n return this.clamp(\n newX,\n this.sliderWidth,\n this.translateDateToPosition(this.maxSelectedDate)\n );\n }\n\n /**\n * Constrain a proposed value for the maximum (right) slider\n *\n * If the value is greater than the rightmost valid position, then set it to\n * the right edge of the widget (ie widget width - slider width). If the value\n * is less than the leftmost valid position (the position of the min slider),\n * then set it to the position of the min slider\n */\n private validMaxSliderX(newX: number): number {\n if (Number.isNaN(newX)) {\n return this.width - this.sliderWidth;\n }\n return this.clamp(\n newX,\n this.translateDateToPosition(this.minSelectedDate),\n this.width - this.sliderWidth\n );\n }\n\n private addListeners(): void {\n window.addEventListener('pointermove', this.move);\n window.addEventListener('pointerup', this.drop);\n window.addEventListener('pointercancel', this.drop);\n }\n\n private removeListeners(): void {\n window.removeEventListener('pointermove', this.move);\n window.removeEventListener('pointerup', this.drop);\n window.removeEventListener('pointercancel', this.drop);\n }\n\n /**\n * start a timer to emit an update event. this timer can be canceled (and the\n * event not emitted) if user drags a slider or focuses a date input within\n * the update delay\n */\n private beginEmitUpdateProcess(): void {\n this.cancelPendingUpdateEvent();\n this._emitUpdatedEventTimer = setTimeout(() => {\n if (this.currentDateRangeString === this._previousDateRange) {\n // don't emit duplicate event if no change since last emitted event\n return;\n }\n this._previousDateRange = this.currentDateRangeString;\n const options = {\n detail: {\n minDate: this.minSelectedDate,\n maxDate: this.maxSelectedDate,\n },\n bubbles: true,\n composed: true,\n };\n this.dispatchEvent(new CustomEvent('histogramDateRangeUpdated', options));\n }, this.updateDelay);\n }\n\n private cancelPendingUpdateEvent(): void {\n if (this._emitUpdatedEventTimer === undefined) {\n return;\n }\n clearTimeout(this._emitUpdatedEventTimer);\n this._emitUpdatedEventTimer = undefined;\n }\n\n /**\n * find position of pointer in relation to the current slider\n */\n private setDragOffset(e: PointerEvent): void {\n this._currentSlider = e.currentTarget as SVGRectElement;\n const sliderX =\n (this._currentSlider.id as SliderId) === 'slider-min'\n ? this.minSliderX\n : this.maxSliderX;\n this._dragOffset = e.offsetX - sliderX;\n // work around Firefox issue where e.offsetX seems to be not based on current\n // element but on background element\n if (\n this._dragOffset > this.sliderWidth ||\n this._dragOffset < -this.sliderWidth\n ) {\n this._dragOffset = 0;\n }\n }\n\n /**\n * @param x horizontal position of slider\n * @returns string representation of date\n */\n private translatePositionToDate(x: number): string {\n // use Math.ceil to round up to fix case where input like 1/1/2010 would get\n // translated to 12/31/2009\n const milliseconds = Math.ceil(\n ((x - this.sliderWidth) * this.dateRangeMS) / this._histWidth\n );\n return this.formatDate(this._minDateMS + milliseconds);\n }\n\n /**\n * Returns slider x-position corresponding to given date (or null if invalid\n * date)\n *\n * @param date\n * @returns x-position of slider\n */\n private translateDateToPosition(date: string): number {\n const milliseconds = this.getMSFromString(date);\n return (\n this.sliderWidth +\n ((milliseconds - this._minDateMS) * this._histWidth) / this.dateRangeMS\n );\n }\n\n /** ensure that the returned value is between minValue and maxValue */\n private clamp(x: number, minValue: number, maxValue: number): number {\n return Math.min(Math.max(x, minValue), maxValue);\n }\n\n private handleMinDateInput(e: InputEvent): void {\n const target = e.currentTarget as HTMLInputElement;\n this.minSelectedDate = target.value;\n this.beginEmitUpdateProcess();\n }\n\n private handleMaxDateInput(e: InputEvent): void {\n const target = e.currentTarget as HTMLInputElement;\n this.maxSelectedDate = target.value;\n this.beginEmitUpdateProcess();\n }\n\n private handleKeyUp(e: KeyboardEvent): void {\n if (e.key === 'Enter') {\n const target = e.currentTarget as HTMLInputElement;\n target.blur();\n }\n }\n\n private get currentDateRangeString(): string {\n return `${this.minSelectedDate}:${this.maxSelectedDate}`;\n }\n\n private getMSFromString(date: string): number {\n const digitGroupCount = (date.split(/(\\d+)/).length - 1) / 2;\n if (digitGroupCount === 1) {\n // if there's just a single set of digits, assume it's a year\n const dateObj = new Date(0, 0); // start at January 1, 1900\n dateObj.setFullYear(Number(date)); // override year (=> 0099-01-01) = 99 CE\n return dateObj.getTime(); // get time in milliseconds\n }\n return dayjs(date, [this.dateFormat, DATE_FORMAT]).valueOf();\n }\n\n private handleBarClick(e: InputEvent): void {\n const dataset = (e.currentTarget as SVGRectElement).dataset as BarDataset;\n const distanceFromMinSlider =\n this.getMSFromString(dataset.binStart) -\n this.getMSFromString(this.minSelectedDate);\n const distanceFromMaxSlider =\n this.getMSFromString(this.maxSelectedDate) -\n this.getMSFromString(dataset.binEnd);\n // update the selection by moving the nearer slider\n if (distanceFromMinSlider < distanceFromMaxSlider) {\n this.minSelectedDate = dataset.binStart;\n } else {\n this.maxSelectedDate = dataset.binEnd;\n }\n this.beginEmitUpdateProcess();\n }\n\n private get minSliderTemplate(): SVGTemplateResult {\n // width/height in pixels of curved part of the sliders (like\n // border-radius); used as part of a SVG quadratic curve. see\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths#curve_commands\n const cs = SLIDER_CORNER_SIZE;\n\n const sliderShape = `\n M${this.minSliderX},0\n h-${this.sliderWidth - cs}\n q-${cs},0 -${cs},${cs}\n v${this.height - cs * 2}\n q0,${cs} ${cs},${cs}\n h${this.sliderWidth - cs}\n `;\n return this.generateSliderSVG(this.minSliderX, 'slider-min', sliderShape);\n }\n\n private get maxSliderTemplate(): SVGTemplateResult {\n const cs = SLIDER_CORNER_SIZE;\n const sliderShape = `\n M${this.maxSliderX},0\n h${this.sliderWidth - cs}\n q${cs},0 ${cs},${cs}\n v${this.height - cs * 2}\n q0,${cs} -${cs},${cs}\n h-${this.sliderWidth - cs}\n `;\n return this.generateSliderSVG(this.maxSliderX, 'slider-max', sliderShape);\n }\n\n private generateSliderSVG(\n sliderPositionX: number,\n id: SliderId,\n sliderShape: string\n ): SVGTemplateResult {\n // whether the curved part of the slider is facing towards the left (1), ie\n // minimum, or facing towards the right (-1), ie maximum\n const k = id === 'slider-min' ? 1 : -1;\n\n return svg`\n <svg\n id=\"${id}\"\n class=\"\n ${this.disabled ? '' : 'draggable'} \n ${this._isDragging ? 'dragging' : ''}\"\n @pointerdown=\"${this.drag}\"\n >\n <path d=\"${sliderShape} z\" fill=\"${sliderColor}\" />\n <rect\n x=\"${\n sliderPositionX - this.sliderWidth * k + this.sliderWidth * 0.4 * k\n }\"\n y=\"${this.height / 3}\"\n width=\"1\"\n height=\"${this.height / 3}\"\n fill=\"white\"\n />\n <rect\n x=\"${\n sliderPositionX - this.sliderWidth * k + this.sliderWidth * 0.6 * k\n }\"\n y=\"${this.height / 3}\"\n width=\"1\"\n height=\"${this.height / 3}\"\n fill=\"white\"\n />\n </svg>\n `;\n }\n\n get selectedRangeTemplate(): SVGTemplateResult {\n return svg`\n <rect\n x=\"${this.minSliderX}\"\n y=\"0\"\n width=\"${this.maxSliderX - this.minSliderX}\"\n height=\"${this.height}\"\n fill=\"${selectedRangeColor}\"\n />`;\n }\n\n get histogramTemplate(): SVGTemplateResult[] {\n const xScale = this._histWidth / this._numBins;\n const barWidth = xScale - 1;\n let x = this.sliderWidth; // start at the left edge of the histogram\n\n // the stroke-dasharray style below creates a transparent border around the\n // right edge of the bar, which prevents user from encountering a gap\n // between adjacent bars (eg when viewing the tooltips or when trying to\n // extend the range by clicking on a bar)\n return this._histData.map(data => {\n const bar = svg`\n <rect\n class=\"bar\"\n style='stroke-dasharray: 0 ${barWidth} ${data.height} ${barWidth} 0 ${\n data.height\n };'\n x=\"${x}\"\n y=\"${this.height - data.height}\"\n width=\"${barWidth}\"\n height=\"${data.height}\"\n @pointerenter=\"${this.showTooltip}\"\n @pointerleave=\"${this.hideTooltip}\"\n @click=\"${this.handleBarClick}\"\n fill=\"${\n x + barWidth >= this.minSliderX && x <= this.maxSliderX\n ? barIncludedFill\n : barExcludedFill\n }\"\n data-num-items=\"${data.value}\"\n data-bin-start=\"${data.binStart}\"\n data-bin-end=\"${data.binEnd}\"\n />`;\n x += xScale;\n return bar;\n });\n }\n\n private formatDate(dateMS: number): string {\n if (Number.isNaN(dateMS)) {\n return '';\n }\n const date = dayjs(dateMS);\n if (date.year() < 1000) {\n // years before 1000 don't play well with dayjs custom formatting, so fall\n // back to displaying only the year\n return String(date.year());\n }\n return date.format(this.dateFormat);\n }\n\n /**\n * NOTE: we are relying on the lit `live` directive in the template to\n * ensure that the change to minSelectedDate is noticed and the input value\n * gets properly re-rendered. see\n * https://lit.dev/docs/templates/directives/#live\n */\n get minInputTemplate(): TemplateResult {\n return html`\n <input\n id=\"date-min\"\n placeholder=\"${this.dateFormat}\"\n type=\"text\"\n @focus=\"${this.cancelPendingUpdateEvent}\"\n @blur=\"${this.handleMinDateInput}\"\n @keyup=\"${this.handleKeyUp}\"\n .value=\"${live(this.minSelectedDate)}\"\n ?disabled=\"${this.disabled}\"\n />\n `;\n }\n\n get maxInputTemplate(): TemplateResult {\n return html`\n <input\n id=\"date-max\"\n placeholder=\"${this.dateFormat}\"\n type=\"text\"\n @focus=\"${this.cancelPendingUpdateEvent}\"\n @blur=\"${this.handleMaxDateInput}\"\n @keyup=\"${this.handleKeyUp}\"\n .value=\"${live(this.maxSelectedDate)}\"\n ?disabled=\"${this.disabled}\"\n />\n `;\n }\n\n get tooltipTemplate(): TemplateResult {\n return html`\n <style>\n #tooltip {\n width: ${this.tooltipWidth}px;\n height: ${this.tooltipHeight}px;\n top: ${-9 - this.tooltipHeight}px;\n left: ${this._tooltipOffset}px;\n display: ${this._tooltipVisible ? 'block' : 'none'};\n }\n #tooltip:after {\n left: ${this.tooltipWidth / 2}px;\n }\n </style>\n <div id=\"tooltip\">${this._tooltipContent}</div>\n `;\n }\n\n private get noDataTemplate(): TemplateResult {\n return html`\n <div class=\"missing-data-message\">${this.missingDataMessage}</div>\n `;\n }\n\n private get activityIndicatorTemplate(): TemplateResult | typeof nothing {\n if (!this.loading) {\n return nothing;\n }\n return html`\n <ia-activity-indicator mode=\"processing\"> </ia-activity-indicator>\n `;\n }\n\n static styles = css`\n .missing-data-message {\n text-align: center;\n }\n #container {\n margin: 0;\n touch-action: none;\n position: relative;\n }\n .disabled {\n opacity: 0.3;\n }\n ia-activity-indicator {\n position: absolute;\n left: calc(50% - 10px);\n top: 10px;\n width: 20px;\n height: 20px;\n --activityIndicatorLoadingDotColor: rgba(0, 0, 0, 0);\n --activityIndicatorLoadingRingColor: ${activityIndicatorColor};\n }\n\n /* prevent selection from interfering with tooltip, especially on mobile */\n /* https://stackoverflow.com/a/4407335/1163042 */\n .noselect {\n -webkit-touch-callout: none; /* iOS Safari */\n -webkit-user-select: none; /* Safari */\n -moz-user-select: none; /* Old versions of Firefox */\n -ms-user-select: none; /* Internet Explorer/Edge */\n user-select: none; /* current Chrome, Edge, Opera and Firefox */\n }\n .bar {\n /* create a transparent border around the hist bars to prevent \"gaps\" and\n flickering when moving around between bars. this also helps with handling\n clicks on the bars, preventing users from being able to click in between\n bars */\n stroke: rgba(0, 0, 0, 0);\n /* ensure transparent stroke wide enough to cover gap between bars */\n stroke-width: 2px;\n }\n .bar:hover {\n /* highlight currently hovered bar */\n fill-opacity: 0.7;\n }\n .disabled .bar:hover {\n /* ensure no visual hover interaction when disabled */\n fill-opacity: 1;\n }\n /****** histogram ********/\n #tooltip {\n position: absolute;\n background: ${tooltipBackgroundColor};\n color: ${tooltipTextColor};\n text-align: center;\n border-radius: 3px;\n padding: 2px;\n font-size: ${tooltipFontSize};\n font-family: ${tooltipFontFamily};\n touch-action: none;\n pointer-events: none;\n }\n #tooltip:after {\n content: '';\n position: absolute;\n margin-left: -5px;\n top: 100%;\n /* arrow */\n border: 5px solid ${tooltipTextColor};\n border-color: ${tooltipBackgroundColor} transparent transparent\n transparent;\n }\n /****** slider ********/\n .draggable:hover {\n cursor: grab;\n }\n .dragging {\n cursor: grabbing !important;\n }\n /****** inputs ********/\n #inputs {\n display: flex;\n justify-content: center;\n }\n #inputs .dash {\n position: relative;\n bottom: -1px;\n }\n input {\n width: ${inputWidth};\n margin: 0 3px;\n border: ${inputBorder};\n border-radius: 2px !important;\n text-align: center;\n font-size: ${inputFontSize};\n font-family: ${inputFontFamily};\n }\n `;\n\n render(): TemplateResult {\n if (!this.hasBinData) {\n return this.noDataTemplate;\n }\n return html`\n <div\n id=\"container\"\n class=\"\n noselect \n ${this._isDragging ? 'dragging' : ''}\n \"\n style=\"width: ${this.width}px\"\n >\n ${this.activityIndicatorTemplate} ${this.tooltipTemplate}\n <div\n class=\"inner-container\n ${this.disabled ? 'disabled' : ''}\"\n >\n <svg\n width=\"${this.width}\"\n height=\"${this.height}\"\n @pointerleave=\"${this.drop}\"\n >\n ${this.selectedRangeTemplate}\n <svg id=\"histogram\">${this.histogramTemplate}</svg>\n ${this.minSliderTemplate} ${this.maxSliderTemplate}\n </svg>\n <div id=\"inputs\">\n ${this.minInputTemplate}\n <div class=\"dash\">-</div>\n ${this.maxInputTemplate}\n </div>\n </div>\n </div>\n `;\n }\n}\n\n// help TypeScript provide strong typing when interacting with DOM APIs\n// https://stackoverflow.com/questions/65148695/lit-element-typescript-project-global-interface-declaration-necessary\ndeclare global {\n interface HTMLElementTagNameMap {\n 'histogram-date-range': HistogramDateRange;\n }\n}\n"]}
1
+ {"version":3,"file":"histogram-date-range.js","sourceRoot":"","sources":["../../src/histogram-date-range.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n nothing,\n LitElement,\n PropertyValues,\n svg,\n SVGTemplateResult,\n TemplateResult,\n} from 'lit';\nimport { property, state, customElement } from 'lit/decorators.js';\nimport { live } from 'lit/directives/live.js';\nimport dayjs from 'dayjs/esm/index.js';\nimport customParseFormat from 'dayjs/esm/plugin/customParseFormat';\ndayjs.extend(customParseFormat);\nimport '@internetarchive/ia-activity-indicator/ia-activity-indicator';\n\n// these values can be overridden via the component's HTML (camelCased) attributes\nconst WIDTH = 180;\nconst HEIGHT = 40;\nconst SLIDER_WIDTH = 10;\nconst TOOLTIP_WIDTH = 125;\nconst TOOLTIP_HEIGHT = 30;\nconst DATE_FORMAT = 'YYYY';\nconst MISSING_DATA = 'no data';\nconst UPDATE_DEBOUNCE_DELAY_MS = 0;\n\n// this constant is not set up to be overridden\nconst SLIDER_CORNER_SIZE = 4;\n\n// these CSS custom props can be overridden from the HTML that is invoking this component\nconst sliderColor = css`var(--histogramDateRangeSliderColor, #4B65FE)`;\nconst selectedRangeColor = css`var(--histogramDateRangeSelectedRangeColor, #DBE0FF)`;\nconst barIncludedFill = css`var(--histogramDateRangeBarIncludedFill, #2C2C2C)`;\nconst activityIndicatorColor = css`var(--histogramDateRangeActivityIndicator, #2C2C2C)`;\nconst barExcludedFill = css`var(--histogramDateRangeBarExcludedFill, #CCCCCC)`;\nconst inputBorder = css`var(--histogramDateRangeInputBorder, 0.5px solid #2C2C2C)`;\nconst inputWidth = css`var(--histogramDateRangeInputWidth, 35px)`;\nconst inputFontSize = css`var(--histogramDateRangeInputFontSize, 1.2rem)`;\nconst inputFontFamily = css`var(--histogramDateRangeInputFontFamily, sans-serif)`;\nconst tooltipBackgroundColor = css`var(--histogramDateRangeTooltipBackgroundColor, #2C2C2C)`;\nconst tooltipTextColor = css`var(--histogramDateRangeTooltipTextColor, #FFFFFF)`;\nconst tooltipFontSize = css`var(--histogramDateRangeTooltipFontSize, 1.1rem)`;\nconst tooltipFontFamily = css`var(--histogramDateRangeTooltipFontFamily, sans-serif)`;\n\ntype SliderId = 'slider-min' | 'slider-max';\n\ninterface HistogramItem {\n value: number;\n height: number;\n binStart: string;\n binEnd: string;\n}\n\ninterface BarDataset extends DOMStringMap {\n numItems: string;\n binStart: string;\n binEnd: string;\n}\n\n@customElement('histogram-date-range')\nexport class HistogramDateRange extends LitElement {\n /* eslint-disable lines-between-class-members */\n\n // public reactive properties that can be set via HTML attributes\n @property({ type: Number }) width = WIDTH;\n @property({ type: Number }) height = HEIGHT;\n @property({ type: Number }) sliderWidth = SLIDER_WIDTH;\n @property({ type: Number }) tooltipWidth = TOOLTIP_WIDTH;\n @property({ type: Number }) tooltipHeight = TOOLTIP_HEIGHT;\n @property({ type: Number }) updateDelay = UPDATE_DEBOUNCE_DELAY_MS;\n @property() dateFormat = DATE_FORMAT;\n @property() missingDataMessage = MISSING_DATA;\n @property() minDate = '';\n @property() maxDate = '';\n @property({ type: Boolean }) disabled = false;\n @property({ type: Object }) bins: number[] = [];\n\n // internal reactive properties not exposed as attributes\n @state() private _tooltipOffset = 0;\n @state() private _tooltipContent?: TemplateResult;\n @state() private _tooltipVisible = false;\n @state() private _isDragging = false;\n @state() private _isLoading = false;\n\n // non-reactive properties (changes don't auto-trigger re-rendering)\n private _minSelectedDate = '';\n private _maxSelectedDate = '';\n private _minDateMS = 0;\n private _maxDateMS = 0;\n private _dragOffset = 0;\n private _histWidth = 0;\n private _binWidth = 0;\n private _currentSlider?: SVGRectElement;\n private _histData: HistogramItem[] = [];\n private _emitUpdatedEventTimer?: ReturnType<typeof setTimeout>;\n private _previousDateRange = '';\n\n /* eslint-enable lines-between-class-members */\n\n disconnectedCallback(): void {\n this.removeListeners();\n super.disconnectedCallback();\n }\n\n updated(changedProps: PropertyValues): void {\n // check for changes that would affect bin data calculations\n if (\n changedProps.has('bins') ||\n changedProps.has('minDate') ||\n changedProps.has('maxDate') ||\n changedProps.has('minSelectedDate') ||\n changedProps.has('maxSelectedDate')\n ) {\n this.handleDataUpdate();\n }\n }\n\n /**\n * Set private properties that depend on the attribute bin data\n *\n * We're caching these values and not using getters to avoid recalculating all\n * of the hist data every time the user drags a slider or hovers over a bar\n * creating a tooltip.\n */\n private handleDataUpdate(): void {\n if (!this.hasBinData) {\n return;\n }\n this._histWidth = this.width - this.sliderWidth * 2;\n this._minDateMS = this.getMSFromString(this.minDate);\n this._maxDateMS = this.getMSFromString(this.maxDate);\n this._binWidth = this._histWidth / this._numBins;\n this._previousDateRange = this.currentDateRangeString;\n this._histData = this.calculateHistData();\n this.minSelectedDate = this.minSelectedDate\n ? this.minSelectedDate\n : this.minDate;\n this.maxSelectedDate = this.maxSelectedDate\n ? this.maxSelectedDate\n : this.maxDate;\n this.requestUpdate();\n }\n\n private calculateHistData(): HistogramItem[] {\n const minValue = Math.min(...this.bins);\n const maxValue = Math.max(...this.bins);\n // if there is no difference between the min and max values, use a range of\n // 1 because log scaling will fail if the range is 0\n const valueRange = minValue === maxValue ? 1 : Math.log1p(maxValue);\n const valueScale = this.height / valueRange;\n const dateScale = this.dateRangeMS / this._numBins;\n return this.bins.map((v: number, i: number) => {\n return {\n value: v,\n // use log scaling for the height of the bar to prevent tall bars from\n // making the smaller ones too small to see\n height: Math.floor(Math.log1p(v) * valueScale),\n binStart: `${this.formatDate(i * dateScale + this._minDateMS)}`,\n binEnd: `${this.formatDate((i + 1) * dateScale + this._minDateMS)}`,\n };\n });\n }\n\n private get hasBinData(): boolean {\n return this._numBins > 0;\n }\n\n private get _numBins(): number {\n if (!this.bins || !this.bins.length) {\n return 0;\n }\n return this.bins.length;\n }\n\n private get histogramLeftEdgeX(): number {\n return this.sliderWidth;\n }\n\n private get histogramRightEdgeX(): number {\n return this.width - this.sliderWidth;\n }\n\n /** component's loading (and disabled) state */\n @property({ type: Boolean }) get loading(): boolean {\n return this._isLoading;\n }\n\n set loading(value: boolean) {\n this.disabled = value;\n this._isLoading = value;\n }\n\n /** formatted minimum date of selected date range */\n @property() get minSelectedDate(): string {\n return this.formatDate(this.getMSFromString(this._minSelectedDate));\n }\n\n /** updates minSelectedDate if new date is valid */\n set minSelectedDate(rawDate: string) {\n if (!this._minSelectedDate) {\n // because the values needed to calculate valid max/min values are not\n // available during the lit init when it's populating properties from\n // attributes, fall back to just the raw date if nothing is already set\n this._minSelectedDate = rawDate;\n return;\n }\n const proposedDateMS = this.getMSFromString(rawDate);\n const isValidDate = !Number.isNaN(proposedDateMS);\n const isNotTooRecent =\n proposedDateMS <= this.getMSFromString(this.maxSelectedDate);\n if (isValidDate && isNotTooRecent) {\n this._minSelectedDate = this.formatDate(proposedDateMS);\n }\n this.requestUpdate();\n }\n\n /** formatted maximum date of selected date range */\n @property() get maxSelectedDate(): string {\n return this.formatDate(this.getMSFromString(this._maxSelectedDate));\n }\n\n /** updates maxSelectedDate if new date is valid */\n set maxSelectedDate(rawDate: string) {\n if (!this._maxSelectedDate) {\n // because the values needed to calculate valid max/min values are not\n // available during the lit init when it's populating properties from\n // attributes, fall back to just the raw date if nothing is already set\n this._maxSelectedDate = rawDate;\n return;\n }\n const proposedDateMS = this.getMSFromString(rawDate);\n const isValidDate = !Number.isNaN(proposedDateMS);\n const isNotTooOld =\n proposedDateMS >= this.getMSFromString(this.minSelectedDate);\n if (isValidDate && isNotTooOld) {\n this._maxSelectedDate = this.formatDate(proposedDateMS);\n }\n this.requestUpdate();\n }\n\n /** horizontal position of min date slider */\n get minSliderX(): number {\n const x = this.translateDateToPosition(this.minSelectedDate);\n return this.validMinSliderX(x);\n }\n\n /** horizontal position of max date slider */\n get maxSliderX(): number {\n const x = this.translateDateToPosition(this.maxSelectedDate);\n return this.validMaxSliderX(x);\n }\n\n private get dateRangeMS(): number {\n return this._maxDateMS - this._minDateMS;\n }\n\n private showTooltip(e: PointerEvent): void {\n if (this._isDragging || this.disabled) {\n return;\n }\n const target = e.currentTarget as SVGRectElement;\n const x = target.x.baseVal.value + this.sliderWidth / 2;\n const dataset = target.dataset as BarDataset;\n const itemsText = `item${dataset.numItems !== '1' ? 's' : ''}`;\n const formattedNumItems = Number(dataset.numItems).toLocaleString();\n\n this._tooltipOffset =\n x + (this._binWidth - this.sliderWidth - this.tooltipWidth) / 2;\n\n this._tooltipContent = html`\n ${formattedNumItems} ${itemsText}<br />\n ${dataset.binStart} - ${dataset.binEnd}\n `;\n this._tooltipVisible = true;\n }\n\n private hideTooltip(): void {\n this._tooltipContent = undefined;\n this._tooltipVisible = false;\n }\n\n // use arrow functions (rather than standard JS class instance methods) so\n // that `this` is bound to the histogramDateRange object and not the event\n // target. for more info see\n // https://lit-element.polymer-project.org/guide/events#using-this-in-event-listeners\n private drag = (e: PointerEvent): void => {\n // prevent selecting text or other ranges while dragging, especially in Safari\n e.preventDefault();\n if (this.disabled) {\n return;\n }\n this.setDragOffset(e);\n this._isDragging = true;\n this.addListeners();\n this.cancelPendingUpdateEvent();\n };\n\n private drop = (): void => {\n if (this._isDragging) {\n this.removeListeners();\n this.beginEmitUpdateProcess();\n }\n this._isDragging = false;\n };\n\n /**\n * Adjust the date range based on slider movement\n *\n * @param e PointerEvent from the slider being moved\n */\n private move = (e: PointerEvent): void => {\n const newX = e.offsetX - this._dragOffset;\n const slider = this._currentSlider as SVGRectElement;\n if ((slider.id as SliderId) === 'slider-min') {\n this.minSelectedDate = this.translatePositionToDate(\n this.validMinSliderX(newX)\n );\n } else {\n this.maxSelectedDate = this.translatePositionToDate(\n this.validMaxSliderX(newX)\n );\n }\n };\n\n /**\n * Constrain a proposed value for the minimum (left) slider\n *\n * If the value is less than the leftmost valid position, then set it to the\n * left edge of the histogram (ie the slider width). If the value is greater\n * than the rightmost valid position (the position of the max slider), then\n * set it to the position of the max slider\n */\n private validMinSliderX(newX: number): number {\n // allow the left slider to go right only to the right slider, even if the\n // max selected date is out of range\n const rightLimit = Math.min(\n this.translateDateToPosition(this.maxSelectedDate),\n this.histogramRightEdgeX\n );\n newX = this.clamp(newX, this.histogramLeftEdgeX, rightLimit);\n const isInvalid =\n Number.isNaN(newX) || rightLimit < this.histogramLeftEdgeX;\n return isInvalid ? this.histogramLeftEdgeX : newX;\n }\n\n /**\n * Constrain a proposed value for the maximum (right) slider\n *\n * If the value is greater than the rightmost valid position, then set it to\n * the right edge of the histogram (ie histogram width - slider width). If the\n * value is less than the leftmost valid position (the position of the min\n * slider), then set it to the position of the min slider\n */\n private validMaxSliderX(newX: number): number {\n // allow the right slider to go left only to the left slider, even if the\n // min selected date is out of range\n const leftLimit = Math.max(\n this.histogramLeftEdgeX,\n this.translateDateToPosition(this.minSelectedDate)\n );\n newX = this.clamp(newX, leftLimit, this.histogramRightEdgeX);\n const isInvalid =\n Number.isNaN(newX) || leftLimit > this.histogramRightEdgeX;\n return isInvalid ? this.histogramRightEdgeX : newX;\n }\n\n private addListeners(): void {\n window.addEventListener('pointermove', this.move);\n window.addEventListener('pointerup', this.drop);\n window.addEventListener('pointercancel', this.drop);\n }\n\n private removeListeners(): void {\n window.removeEventListener('pointermove', this.move);\n window.removeEventListener('pointerup', this.drop);\n window.removeEventListener('pointercancel', this.drop);\n }\n\n /**\n * start a timer to emit an update event. this timer can be canceled (and the\n * event not emitted) if user drags a slider or focuses a date input within\n * the update delay\n */\n private beginEmitUpdateProcess(): void {\n this.cancelPendingUpdateEvent();\n this._emitUpdatedEventTimer = setTimeout(() => {\n if (this.currentDateRangeString === this._previousDateRange) {\n // don't emit duplicate event if no change since last emitted event\n return;\n }\n this._previousDateRange = this.currentDateRangeString;\n const options = {\n detail: {\n minDate: this.minSelectedDate,\n maxDate: this.maxSelectedDate,\n },\n bubbles: true,\n composed: true,\n };\n this.dispatchEvent(new CustomEvent('histogramDateRangeUpdated', options));\n }, this.updateDelay);\n }\n\n private cancelPendingUpdateEvent(): void {\n if (this._emitUpdatedEventTimer === undefined) {\n return;\n }\n clearTimeout(this._emitUpdatedEventTimer);\n this._emitUpdatedEventTimer = undefined;\n }\n\n /**\n * find position of pointer in relation to the current slider\n */\n private setDragOffset(e: PointerEvent): void {\n this._currentSlider = e.currentTarget as SVGRectElement;\n const sliderX =\n (this._currentSlider.id as SliderId) === 'slider-min'\n ? this.minSliderX\n : this.maxSliderX;\n this._dragOffset = e.offsetX - sliderX;\n // work around Firefox issue where e.offsetX seems to be not based on current\n // element but on background element\n if (\n this._dragOffset > this.sliderWidth ||\n this._dragOffset < -this.sliderWidth\n ) {\n this._dragOffset = 0;\n }\n }\n\n /**\n * @param x horizontal position of slider\n * @returns string representation of date\n */\n private translatePositionToDate(x: number): string {\n // use Math.ceil to round up to fix case where input like 1/1/2010 would get\n // translated to 12/31/2009\n const milliseconds = Math.ceil(\n ((x - this.sliderWidth) * this.dateRangeMS) / this._histWidth\n );\n return this.formatDate(this._minDateMS + milliseconds);\n }\n\n /**\n * Returns slider x-position corresponding to given date\n *\n * @param date\n * @returns x-position of slider\n */\n private translateDateToPosition(date: string): number {\n const milliseconds = this.getMSFromString(date);\n return (\n this.sliderWidth +\n ((milliseconds - this._minDateMS) * this._histWidth) / this.dateRangeMS\n );\n }\n\n /** ensure that the returned value is between minValue and maxValue */\n private clamp(x: number, minValue: number, maxValue: number): number {\n return Math.min(Math.max(x, minValue), maxValue);\n }\n\n private handleMinDateInput(e: Event): void {\n const target = e.currentTarget as HTMLInputElement;\n this.minSelectedDate = target.value;\n this.beginEmitUpdateProcess();\n }\n\n private handleMaxDateInput(e: Event): void {\n const target = e.currentTarget as HTMLInputElement;\n this.maxSelectedDate = target.value;\n this.beginEmitUpdateProcess();\n }\n\n private handleKeyUp(e: KeyboardEvent): void {\n if (e.key === 'Enter') {\n const target = e.currentTarget as HTMLInputElement;\n target.blur();\n if (target.id === 'date-min') {\n this.handleMinDateInput(e);\n } else if (target.id === 'date-max') {\n this.handleMaxDateInput(e);\n }\n }\n }\n\n private get currentDateRangeString(): string {\n return `${this.minSelectedDate}:${this.maxSelectedDate}`;\n }\n\n private getMSFromString(date: string): number {\n const digitGroupCount = (date.split(/(\\d+)/).length - 1) / 2;\n if (digitGroupCount === 1) {\n // if there's just a single set of digits, assume it's a year\n const dateObj = new Date(0, 0); // start at January 1, 1900\n dateObj.setFullYear(Number(date)); // override year\n return dateObj.getTime(); // get time in milliseconds\n }\n return dayjs(date, [this.dateFormat, DATE_FORMAT]).valueOf();\n }\n\n /**\n * expand or narrow the selected range by moving the slider nearest the\n * clicked bar to the outer edge of the clicked bar\n *\n * @param e Event click event from a histogram bar\n */\n private handleBarClick(e: Event): void {\n const dataset = (e.currentTarget as SVGRectElement).dataset as BarDataset;\n // use the midpoint of the width of the clicked bar to determine which is\n // the nearest slider\n const clickPosition =\n (this.getMSFromString(dataset.binStart) +\n this.getMSFromString(dataset.binEnd)) /\n 2;\n const distanceFromMinSlider = Math.abs(\n clickPosition - this.getMSFromString(this.minSelectedDate)\n );\n const distanceFromMaxSlider = Math.abs(\n clickPosition - this.getMSFromString(this.maxSelectedDate)\n );\n // update the selected range by moving the nearer slider\n if (distanceFromMinSlider < distanceFromMaxSlider) {\n this.minSelectedDate = dataset.binStart;\n } else {\n this.maxSelectedDate = dataset.binEnd;\n }\n this.beginEmitUpdateProcess();\n }\n\n private get minSliderTemplate(): SVGTemplateResult {\n // width/height in pixels of curved part of the sliders (like\n // border-radius); used as part of a SVG quadratic curve. see\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths#curve_commands\n const cs = SLIDER_CORNER_SIZE;\n\n const sliderShape = `\n M${this.minSliderX},0\n h-${this.sliderWidth - cs}\n q-${cs},0 -${cs},${cs}\n v${this.height - cs * 2}\n q0,${cs} ${cs},${cs}\n h${this.sliderWidth - cs}\n `;\n return this.generateSliderSVG(this.minSliderX, 'slider-min', sliderShape);\n }\n\n private get maxSliderTemplate(): SVGTemplateResult {\n const cs = SLIDER_CORNER_SIZE;\n const sliderShape = `\n M${this.maxSliderX},0\n h${this.sliderWidth - cs}\n q${cs},0 ${cs},${cs}\n v${this.height - cs * 2}\n q0,${cs} -${cs},${cs}\n h-${this.sliderWidth - cs}\n `;\n return this.generateSliderSVG(this.maxSliderX, 'slider-max', sliderShape);\n }\n\n private generateSliderSVG(\n sliderPositionX: number,\n id: SliderId,\n sliderShape: string\n ): SVGTemplateResult {\n // whether the curved part of the slider is facing towards the left (1), ie\n // minimum, or facing towards the right (-1), ie maximum\n const k = id === 'slider-min' ? 1 : -1;\n\n return svg`\n <svg\n id=\"${id}\"\n class=\"\n ${this.disabled ? '' : 'draggable'} \n ${this._isDragging ? 'dragging' : ''}\"\n @pointerdown=\"${this.drag}\"\n >\n <path d=\"${sliderShape} z\" fill=\"${sliderColor}\" />\n <rect\n x=\"${\n sliderPositionX - this.sliderWidth * k + this.sliderWidth * 0.4 * k\n }\"\n y=\"${this.height / 3}\"\n width=\"1\"\n height=\"${this.height / 3}\"\n fill=\"white\"\n />\n <rect\n x=\"${\n sliderPositionX - this.sliderWidth * k + this.sliderWidth * 0.6 * k\n }\"\n y=\"${this.height / 3}\"\n width=\"1\"\n height=\"${this.height / 3}\"\n fill=\"white\"\n />\n </svg>\n `;\n }\n\n get selectedRangeTemplate(): SVGTemplateResult {\n return svg`\n <rect\n x=\"${this.minSliderX}\"\n y=\"0\"\n width=\"${this.maxSliderX - this.minSliderX}\"\n height=\"${this.height}\"\n fill=\"${selectedRangeColor}\"\n />`;\n }\n\n get histogramTemplate(): SVGTemplateResult[] {\n const xScale = this._histWidth / this._numBins;\n const barWidth = xScale - 1;\n let x = this.sliderWidth; // start at the left edge of the histogram\n\n // the stroke-dasharray style below creates a transparent border around the\n // right edge of the bar, which prevents user from encountering a gap\n // between adjacent bars (eg when viewing the tooltips or when trying to\n // extend the range by clicking on a bar)\n return this._histData.map(data => {\n const bar = svg`\n <rect\n class=\"bar\"\n style='stroke-dasharray: 0 ${barWidth} ${data.height} ${barWidth} 0 ${\n data.height\n };'\n x=\"${x}\"\n y=\"${this.height - data.height}\"\n width=\"${barWidth}\"\n height=\"${data.height}\"\n @pointerenter=\"${this.showTooltip}\"\n @pointerleave=\"${this.hideTooltip}\"\n @click=\"${this.handleBarClick}\"\n fill=\"${\n x + barWidth >= this.minSliderX && x <= this.maxSliderX\n ? barIncludedFill\n : barExcludedFill\n }\"\n data-num-items=\"${data.value}\"\n data-bin-start=\"${data.binStart}\"\n data-bin-end=\"${data.binEnd}\"\n />`;\n x += xScale;\n return bar;\n });\n }\n\n private formatDate(dateMS: number): string {\n if (Number.isNaN(dateMS)) {\n return '';\n }\n const date = dayjs(dateMS);\n if (date.year() < 1000) {\n // years before 1000 don't play well with dayjs custom formatting, so fall\n // back to displaying only the year\n return String(date.year());\n }\n return date.format(this.dateFormat);\n }\n\n /**\n * NOTE: we are relying on the lit `live` directive in the template to\n * ensure that the change to minSelectedDate is noticed and the input value\n * gets properly re-rendered. see\n * https://lit.dev/docs/templates/directives/#live\n */\n get minInputTemplate(): TemplateResult {\n return html`\n <input\n id=\"date-min\"\n placeholder=\"${this.dateFormat}\"\n type=\"text\"\n @focus=\"${this.cancelPendingUpdateEvent}\"\n @blur=\"${this.handleMinDateInput}\"\n @keyup=\"${this.handleKeyUp}\"\n .value=\"${live(this.minSelectedDate)}\"\n ?disabled=\"${this.disabled}\"\n />\n `;\n }\n\n get maxInputTemplate(): TemplateResult {\n return html`\n <input\n id=\"date-max\"\n placeholder=\"${this.dateFormat}\"\n type=\"text\"\n @focus=\"${this.cancelPendingUpdateEvent}\"\n @blur=\"${this.handleMaxDateInput}\"\n @keyup=\"${this.handleKeyUp}\"\n .value=\"${live(this.maxSelectedDate)}\"\n ?disabled=\"${this.disabled}\"\n />\n `;\n }\n\n get tooltipTemplate(): TemplateResult {\n return html`\n <style>\n #tooltip {\n width: ${this.tooltipWidth}px;\n height: ${this.tooltipHeight}px;\n top: ${-9 - this.tooltipHeight}px;\n left: ${this._tooltipOffset}px;\n display: ${this._tooltipVisible ? 'block' : 'none'};\n }\n #tooltip:after {\n left: ${this.tooltipWidth / 2}px;\n }\n </style>\n <div id=\"tooltip\">${this._tooltipContent}</div>\n `;\n }\n\n private get noDataTemplate(): TemplateResult {\n return html`\n <div class=\"missing-data-message\">${this.missingDataMessage}</div>\n `;\n }\n\n private get activityIndicatorTemplate(): TemplateResult | typeof nothing {\n if (!this.loading) {\n return nothing;\n }\n return html`\n <ia-activity-indicator mode=\"processing\"> </ia-activity-indicator>\n `;\n }\n\n static styles = css`\n .missing-data-message {\n text-align: center;\n }\n #container {\n margin: 0;\n touch-action: none;\n position: relative;\n }\n .disabled {\n opacity: 0.3;\n }\n ia-activity-indicator {\n position: absolute;\n left: calc(50% - 10px);\n top: 10px;\n width: 20px;\n height: 20px;\n --activityIndicatorLoadingDotColor: rgba(0, 0, 0, 0);\n --activityIndicatorLoadingRingColor: ${activityIndicatorColor};\n }\n\n /* prevent selection from interfering with tooltip, especially on mobile */\n /* https://stackoverflow.com/a/4407335/1163042 */\n .noselect {\n -webkit-touch-callout: none; /* iOS Safari */\n -webkit-user-select: none; /* Safari */\n -moz-user-select: none; /* Old versions of Firefox */\n -ms-user-select: none; /* Internet Explorer/Edge */\n user-select: none; /* current Chrome, Edge, Opera and Firefox */\n }\n .bar {\n /* create a transparent border around the hist bars to prevent \"gaps\" and\n flickering when moving around between bars. this also helps with handling\n clicks on the bars, preventing users from being able to click in between\n bars */\n stroke: rgba(0, 0, 0, 0);\n /* ensure transparent stroke wide enough to cover gap between bars */\n stroke-width: 2px;\n }\n .bar:hover {\n /* highlight currently hovered bar */\n fill-opacity: 0.7;\n }\n .disabled .bar:hover {\n /* ensure no visual hover interaction when disabled */\n fill-opacity: 1;\n }\n /****** histogram ********/\n #tooltip {\n position: absolute;\n background: ${tooltipBackgroundColor};\n color: ${tooltipTextColor};\n text-align: center;\n border-radius: 3px;\n padding: 2px;\n font-size: ${tooltipFontSize};\n font-family: ${tooltipFontFamily};\n touch-action: none;\n pointer-events: none;\n }\n #tooltip:after {\n content: '';\n position: absolute;\n margin-left: -5px;\n top: 100%;\n /* arrow */\n border: 5px solid ${tooltipTextColor};\n border-color: ${tooltipBackgroundColor} transparent transparent\n transparent;\n }\n /****** slider ********/\n .draggable:hover {\n cursor: grab;\n }\n .dragging {\n cursor: grabbing !important;\n }\n /****** inputs ********/\n #inputs {\n display: flex;\n justify-content: center;\n }\n #inputs .dash {\n position: relative;\n bottom: -1px;\n }\n input {\n width: ${inputWidth};\n margin: 0 3px;\n border: ${inputBorder};\n border-radius: 2px !important;\n text-align: center;\n font-size: ${inputFontSize};\n font-family: ${inputFontFamily};\n }\n `;\n\n render(): TemplateResult {\n if (!this.hasBinData) {\n return this.noDataTemplate;\n }\n return html`\n <div\n id=\"container\"\n class=\"\n noselect \n ${this._isDragging ? 'dragging' : ''}\n \"\n style=\"width: ${this.width}px\"\n >\n ${this.activityIndicatorTemplate} ${this.tooltipTemplate}\n <div\n class=\"inner-container\n ${this.disabled ? 'disabled' : ''}\"\n >\n <svg\n width=\"${this.width}\"\n height=\"${this.height}\"\n @pointerleave=\"${this.drop}\"\n >\n ${this.selectedRangeTemplate}\n <svg id=\"histogram\">${this.histogramTemplate}</svg>\n ${this.minSliderTemplate} ${this.maxSliderTemplate}\n </svg>\n <div id=\"inputs\">\n ${this.minInputTemplate}\n <div class=\"dash\">-</div>\n ${this.maxInputTemplate}\n </div>\n </div>\n </div>\n `;\n }\n}\n\n// help TypeScript provide strong typing when interacting with DOM APIs\n// https://stackoverflow.com/questions/65148695/lit-element-typescript-project-global-interface-declaration-necessary\ndeclare global {\n interface HTMLElementTagNameMap {\n 'histogram-date-range': HistogramDateRange;\n }\n}\n"]}
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-debugger */
2
1
  import { html, fixture, expect, oneEvent, aTimeout } from '@open-wc/testing';
3
2
  import '../src/histogram-date-range';
4
3
  const SLIDER_WIDTH = 10;
@@ -48,9 +47,12 @@ describe('HistogramDateRange', () => {
48
47
  /* -------------------------- minimum (left) slider ------------------------- */
49
48
  expect(el.minSliderX).to.eq(SLIDER_WIDTH);
50
49
  const minDateInput = (_a = el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('#date-min');
50
+ const pressEnterEvent = new KeyboardEvent('keyup', {
51
+ key: 'Enter',
52
+ });
51
53
  // valid min date
52
54
  minDateInput.value = '1950';
53
- minDateInput.dispatchEvent(new Event('blur'));
55
+ minDateInput.dispatchEvent(pressEnterEvent);
54
56
  expect(Math.floor(el.minSliderX)).to.eq(84);
55
57
  expect(el.minSelectedDate).to.eq('1/1/1950'); // set to correct format
56
58
  // attempt to set date earlier than first item
@@ -64,8 +66,7 @@ describe('HistogramDateRange', () => {
64
66
  const maxDateInput = (_b = el.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('#date-max');
65
67
  // set valid max date
66
68
  maxDateInput.value = '3/12/1975';
67
- maxDateInput.dispatchEvent(new Event('blur'));
68
- await el.updateComplete;
69
+ maxDateInput.dispatchEvent(pressEnterEvent);
69
70
  expect(Math.floor(el.maxSliderX)).to.eq(121);
70
71
  expect(maxDateInput.value).to.eq('3/12/1975');
71
72
  // attempt to set date later than last item
@@ -272,11 +273,34 @@ describe('HistogramDateRange', () => {
272
273
  `);
273
274
  const leftBarToClick = Array.from((_a = el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.bar'))[1]; // click on second bar to the left
274
275
  leftBarToClick.dispatchEvent(new Event('click'));
276
+ await el.updateComplete;
275
277
  expect(el.minSelectedDate).to.eq('1910'); // range was extended to left
276
278
  const rightBarToClick = Array.from((_b = el.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelectorAll('.bar'))[8]; // click on second bar from the right
277
279
  rightBarToClick.dispatchEvent(new Event('click'));
278
280
  expect(el.maxSelectedDate).to.eq('1998'); // range was extended to right
279
281
  });
282
+ it('narrows the selected range when the histogram is clicked inside of the current range', async () => {
283
+ var _a, _b;
284
+ const el = await fixture(html `
285
+ <histogram-date-range
286
+ minDate="1900"
287
+ maxDate="2020"
288
+ minSelectedDate="1900"
289
+ maxSelectedDate="2020"
290
+ bins="[33, 1, 1, 1, 10, 10, 1, 1, 1, 50, 100]"
291
+ >
292
+ </histogram-date-range>
293
+ `);
294
+ ///////////////////////////////////////////////
295
+ // NB: the slider nearest the clicked bar moves
296
+ ///////////////////////////////////////////////
297
+ const leftBarToClick = Array.from((_a = el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.bar'))[3]; // click on fourth bar to the left
298
+ leftBarToClick.dispatchEvent(new Event('click'));
299
+ expect(el.minSelectedDate).to.eq('1932'); // range was extended to the right
300
+ const rightBarToClick = Array.from((_b = el.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelectorAll('.bar'))[8]; // click on second bar from the right
301
+ rightBarToClick.dispatchEvent(new Event('click'));
302
+ expect(el.maxSelectedDate).to.eq('1998'); // range was extended to the left
303
+ });
280
304
  it('handles invalid pre-selected range by defaulting to overall max and min', async () => {
281
305
  var _a, _b;
282
306
  const el = await fixture(html `
@@ -296,6 +320,24 @@ describe('HistogramDateRange', () => {
296
320
  // well-formed max date is allowed
297
321
  expect(maxDateInput.value).to.eq('5000');
298
322
  });
323
+ it('handles year values less than 1000 by overriding date format to just display year', async () => {
324
+ var _a, _b;
325
+ const el = await fixture(html `
326
+ <histogram-date-range
327
+ dateFormat="M/D/YYYY"
328
+ minDate="-2000"
329
+ maxDate="2000"
330
+ minSelectedDate="-500"
331
+ maxSelectedDate="500"
332
+ bins="[33, 1, 100]"
333
+ >
334
+ </histogram-date-range>
335
+ `);
336
+ const minDateInput = (_a = el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('#date-min');
337
+ expect(minDateInput.value).to.eq('-500');
338
+ const maxDateInput = (_b = el.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('#date-max');
339
+ expect(maxDateInput.value).to.eq('500');
340
+ });
299
341
  it('handles missing data', async () => {
300
342
  var _a, _b;
301
343
  let el = await fixture(html `<histogram-date-range>
@@ -318,9 +360,18 @@ describe('HistogramDateRange', () => {
318
360
  `);
319
361
  const bars = (_a = el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.bar');
320
362
  const heights = Array.from(bars).map(b => b.height.baseVal.value);
321
- debugger;
322
363
  expect(heights).to.eql([157]);
323
364
  });
365
+ it('correctly displays small diff between max and min values', async () => {
366
+ var _a;
367
+ const el = await fixture(html `
368
+ <histogram-date-range bins="[1519,2643,1880,2041,1638,1441]">
369
+ </histogram-date-range>
370
+ `);
371
+ const bars = (_a = el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.bar');
372
+ const heights = Array.from(bars).map(b => b.height.baseVal.value);
373
+ expect(heights).to.eql([37, 40, 38, 38, 37, 36]);
374
+ });
324
375
  it('has a disabled state', async () => {
325
376
  var _a, _b, _c;
326
377
  const el = await fixture(html `