@internetarchive/histogram-date-range 1.4.0-alpha-webdev7756.0 → 1.4.0-alpha-webdev7756.1
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 +22 -9
- package/demo/js/{lit-histogram-wrapper.ts → app-root.ts} +4 -20
- package/dist/demo/js/app-root.d.ts +1 -2
- package/dist/demo/js/app-root.js +19 -20
- package/dist/demo/js/app-root.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/src/histogram-date-range.d.ts +18 -9
- package/dist/src/histogram-date-range.js +32 -16
- package/dist/src/histogram-date-range.js.map +1 -1
- package/dist/test/histogram-date-range.test.js +19 -1
- package/dist/test/histogram-date-range.test.js.map +1 -1
- package/docs/demo/index.html +22 -9
- package/docs/dist/demo/js/{lit-histogram-wrapper.js → app-root.js} +7 -22
- package/docs/dist/src/histogram-date-range.js +14 -5
- package/index.ts +3 -0
- package/package.json +1 -1
- package/src/histogram-date-range.ts +55 -35
- package/test/histogram-date-range.test.ts +27 -1
|
@@ -20,6 +20,28 @@ import { styleMap } from 'lit/directives/style-map.js';
|
|
|
20
20
|
dayjs.extend(customParseFormat);
|
|
21
21
|
dayjs.extend(fixFirstCenturyYears);
|
|
22
22
|
|
|
23
|
+
type SliderId = 'slider-min' | 'slider-max';
|
|
24
|
+
|
|
25
|
+
export type BinSnappingInterval = 'none' | 'month' | 'year';
|
|
26
|
+
|
|
27
|
+
export type BarScalingPreset = 'linear' | 'logarithmic';
|
|
28
|
+
export type BarScalingFunction = (binValue: number) => number;
|
|
29
|
+
export type BarScalingOption = BarScalingPreset | BarScalingFunction;
|
|
30
|
+
|
|
31
|
+
interface HistogramItem {
|
|
32
|
+
value: number;
|
|
33
|
+
height: number;
|
|
34
|
+
binStart: string;
|
|
35
|
+
binEnd: string;
|
|
36
|
+
tooltip: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface BarDataset extends DOMStringMap {
|
|
40
|
+
numItems: string;
|
|
41
|
+
binStart: string;
|
|
42
|
+
binEnd: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
23
45
|
// these values can be overridden via the component's HTML (camelCased) attributes
|
|
24
46
|
const WIDTH = 180;
|
|
25
47
|
const HEIGHT = 40;
|
|
@@ -31,12 +53,17 @@ const MISSING_DATA = 'no data';
|
|
|
31
53
|
const UPDATE_DEBOUNCE_DELAY_MS = 0;
|
|
32
54
|
const TOOLTIP_LABEL = 'item';
|
|
33
55
|
|
|
34
|
-
// this function may be overridden only via Lit property expression or direct assignment
|
|
35
|
-
const LOG_BAR_SCALING_FN = (binValue: number) => Math.log1p(binValue);
|
|
36
|
-
|
|
37
56
|
// this constant is not set up to be overridden
|
|
38
57
|
const SLIDER_CORNER_SIZE = 4;
|
|
39
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Map from bar scaling preset options to the corresponding function they represent
|
|
61
|
+
*/
|
|
62
|
+
const BAR_SCALING_PRESET_FNS: Record<BarScalingPreset, BarScalingFunction> = {
|
|
63
|
+
linear: (binValue: number) => binValue,
|
|
64
|
+
logarithmic: (binValue: number) => Math.log1p(binValue),
|
|
65
|
+
};
|
|
66
|
+
|
|
40
67
|
// these CSS custom props can be overridden from the HTML that is invoking this component
|
|
41
68
|
const sliderColor = css`var(--histogramDateRangeSliderColor, #4B65FE)`;
|
|
42
69
|
const selectedRangeColor = css`var(--histogramDateRangeSelectedRangeColor, #DBE0FF)`;
|
|
@@ -53,24 +80,6 @@ const tooltipTextColor = css`var(--histogramDateRangeTooltipTextColor, #FFFFFF)`
|
|
|
53
80
|
const tooltipFontSize = css`var(--histogramDateRangeTooltipFontSize, 1.1rem)`;
|
|
54
81
|
const tooltipFontFamily = css`var(--histogramDateRangeTooltipFontFamily, sans-serif)`;
|
|
55
82
|
|
|
56
|
-
type SliderId = 'slider-min' | 'slider-max';
|
|
57
|
-
|
|
58
|
-
export type BinSnappingInterval = 'none' | 'month' | 'year';
|
|
59
|
-
|
|
60
|
-
interface HistogramItem {
|
|
61
|
-
value: number;
|
|
62
|
-
height: number;
|
|
63
|
-
binStart: string;
|
|
64
|
-
binEnd: string;
|
|
65
|
-
tooltip: string;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
interface BarDataset extends DOMStringMap {
|
|
69
|
-
numItems: string;
|
|
70
|
-
binStart: string;
|
|
71
|
-
binEnd: string;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
83
|
@customElement('histogram-date-range')
|
|
75
84
|
export class HistogramDateRange extends LitElement {
|
|
76
85
|
/* eslint-disable lines-between-class-members */
|
|
@@ -111,20 +120,20 @@ export class HistogramDateRange extends LitElement {
|
|
|
111
120
|
@property({ type: String }) tooltipLabel = TOOLTIP_LABEL;
|
|
112
121
|
|
|
113
122
|
/**
|
|
114
|
-
* A function
|
|
115
|
-
*
|
|
123
|
+
* A function or preset value indicating how the height of each bar relates to its
|
|
124
|
+
* corresponding bin value. Current presets available are 'logarithmic' and 'linear',
|
|
125
|
+
* but a custom function may be provided instead if other behavior is desired.
|
|
116
126
|
*
|
|
117
|
-
*
|
|
118
|
-
* bars for smaller values
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
127
|
+
* The default scaling (`'logarithmic'`) uses the logarithm of each bin value, yielding
|
|
128
|
+
* more prominent bars for smaller values. This ensures that even when the difference
|
|
129
|
+
* between the min & max values is large, small values are unlikely to completely disappear
|
|
130
|
+
* visually. However, the cost is that bars have less noticeable variation among values of
|
|
131
|
+
* a similar magnitude, and their heights are not a direct representation of the bin values.
|
|
122
132
|
*
|
|
123
|
-
*
|
|
133
|
+
* The `'linear'` preset option instead sizes the bars in linear proportion to their bin
|
|
134
|
+
* values.
|
|
124
135
|
*/
|
|
125
|
-
@property({
|
|
126
|
-
binValue: number
|
|
127
|
-
) => number = LOG_BAR_SCALING_FN;
|
|
136
|
+
@property({ type: String }) barScaling: BarScalingOption = 'logarithmic';
|
|
128
137
|
|
|
129
138
|
// internal reactive properties not exposed as attributes
|
|
130
139
|
@state() private _tooltipOffsetX = 0;
|
|
@@ -166,7 +175,8 @@ export class HistogramDateRange extends LitElement {
|
|
|
166
175
|
changedProps.has('maxSelectedDate') ||
|
|
167
176
|
changedProps.has('width') ||
|
|
168
177
|
changedProps.has('height') ||
|
|
169
|
-
changedProps.has('binSnapping')
|
|
178
|
+
changedProps.has('binSnapping') ||
|
|
179
|
+
changedProps.has('barScaling')
|
|
170
180
|
) {
|
|
171
181
|
this.handleDataUpdate();
|
|
172
182
|
}
|
|
@@ -265,6 +275,17 @@ export class HistogramDateRange extends LitElement {
|
|
|
265
275
|
}
|
|
266
276
|
}
|
|
267
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Function to scale bin values, whether from a preset or a provided custom function.
|
|
280
|
+
*/
|
|
281
|
+
private get barScalingFunction(): BarScalingFunction {
|
|
282
|
+
if (typeof this.barScaling === 'string') {
|
|
283
|
+
return BAR_SCALING_PRESET_FNS[this.barScaling];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return this.barScaling;
|
|
287
|
+
}
|
|
288
|
+
|
|
268
289
|
private calculateHistData(): HistogramItem[] {
|
|
269
290
|
const { bins, height, dateRangeMS, _numBins, _minDateMS } = this;
|
|
270
291
|
const minValue = Math.min(...this.bins);
|
|
@@ -295,8 +316,7 @@ export class HistogramDateRange extends LitElement {
|
|
|
295
316
|
|
|
296
317
|
return {
|
|
297
318
|
value: v,
|
|
298
|
-
//
|
|
299
|
-
// making the smaller ones too small to see
|
|
319
|
+
// apply the configured scaling function to the bin value before determining bar height
|
|
300
320
|
height: Math.floor(this.barScalingFunction(v) * valueScale),
|
|
301
321
|
binStart,
|
|
302
322
|
binEnd,
|
|
@@ -44,7 +44,7 @@ async function createCustomElementInHTMLContainer(): Promise<HistogramDateRange>
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
describe('HistogramDateRange', () => {
|
|
47
|
-
it('shows scaled histogram bars when provided with data', async () => {
|
|
47
|
+
it('shows log-scaled histogram bars when provided with data', async () => {
|
|
48
48
|
const el = await createCustomElementInHTMLContainer();
|
|
49
49
|
const bars = el.shadowRoot?.querySelectorAll(
|
|
50
50
|
'.bar'
|
|
@@ -54,6 +54,32 @@ describe('HistogramDateRange', () => {
|
|
|
54
54
|
expect(heights).to.eql([38, 7, 50]);
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
it('uses linear bar height scaling when specified', async () => {
|
|
58
|
+
const el = await createCustomElementInHTMLContainer();
|
|
59
|
+
el.barScaling = 'linear';
|
|
60
|
+
await el.updateComplete;
|
|
61
|
+
|
|
62
|
+
const bars = el.shadowRoot?.querySelectorAll(
|
|
63
|
+
'.bar'
|
|
64
|
+
) as unknown as SVGRectElement[];
|
|
65
|
+
const heights = Array.from(bars, b => b.height.baseVal.value);
|
|
66
|
+
|
|
67
|
+
expect(heights).to.eql([16, 0, 50]);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('uses custom bar height scaling when specified', async () => {
|
|
71
|
+
const el = await createCustomElementInHTMLContainer();
|
|
72
|
+
el.barScaling = (x: number) => Math.sqrt(x);
|
|
73
|
+
await el.updateComplete;
|
|
74
|
+
|
|
75
|
+
const bars = el.shadowRoot?.querySelectorAll(
|
|
76
|
+
'.bar'
|
|
77
|
+
) as unknown as SVGRectElement[];
|
|
78
|
+
const heights = Array.from(bars, b => b.height.baseVal.value);
|
|
79
|
+
|
|
80
|
+
expect(heights).to.eql([28, 5, 50]);
|
|
81
|
+
});
|
|
82
|
+
|
|
57
83
|
it('changes the position of the sliders and standardizes date format when dates are entered', async () => {
|
|
58
84
|
const el = await createCustomElementInHTMLContainer();
|
|
59
85
|
|