From 0445599a183c7749962925f131459b06896f47bb Mon Sep 17 00:00:00 2001 From: kyleju Date: Sat, 7 Dec 2024 01:03:11 +0000 Subject: [PATCH] Missing one implementation draft --- .../static/js/components/webstatus-gchart.ts | 14 +- .../js/components/webstatus-stats-page.ts | 157 ++++++++++++++---- 2 files changed, 132 insertions(+), 39 deletions(-) diff --git a/frontend/src/static/js/components/webstatus-gchart.ts b/frontend/src/static/js/components/webstatus-gchart.ts index 35e079d5..1dad9e35 100644 --- a/frontend/src/static/js/components/webstatus-gchart.ts +++ b/frontend/src/static/js/components/webstatus-gchart.ts @@ -65,6 +65,9 @@ export class WebstatusGChart extends LitElement { }) dataObj: WebStatusDataObj | undefined; + @property({attribute: false}) + hasMax!: boolean; + @property({state: true, type: Object}) dataTable: | google.visualization.DataTable @@ -142,10 +145,13 @@ export class WebstatusGChart extends LitElement { augmentOptions( options: google.visualization.ComboChartOptions, ): google.visualization.ComboChartOptions { - options = { - ...options, - tooltip: {trigger: 'selection'}, - }; + if (!this.hasMax) { + options = { + ...options, + tooltip: {trigger: 'selection'}, + }; + return options; + } const numColumns = this.dataTable!.getNumberOfColumns(); // The number of series is the number of columns with role 'data'. diff --git a/frontend/src/static/js/components/webstatus-stats-page.ts b/frontend/src/static/js/components/webstatus-stats-page.ts index 6d21d899..e3f41f1a 100644 --- a/frontend/src/static/js/components/webstatus-stats-page.ts +++ b/frontend/src/static/js/components/webstatus-stats-page.ts @@ -33,8 +33,8 @@ import {apiClientContext} from '../contexts/api-client-context.js'; import './webstatus-gchart'; import {WebStatusDataObj} from './webstatus-gchart.js'; -/** Generate a key for globalFeatureSupport. */ -function globalFeatureSupportKey(browser: BrowsersParameter): string { +/** Generate a key for globalFeatureSupport and missingOneImplementationMap. */ +function statsDataKey(browser: BrowsersParameter): string { return browser; } @@ -47,7 +47,7 @@ export class StatsPage extends LitElement { apiClient!: APIClient; @state() - globalFeatureSupportBrowsers: BrowsersParameter[] = ALL_BROWSERS; + supportedBrowsers: BrowsersParameter[] = ALL_BROWSERS; @state() // Default: Date.now() - 1 year. @@ -57,7 +57,7 @@ export class StatsPage extends LitElement { endDate: Date = new Date(); // Today // Map from browser-channel to global feature support. - // The key is generated by globalFeatureSupportKey(). + // The key is generated by statsDataKey(). @state() globalFeatureSupport = new Map>(); @@ -67,6 +67,15 @@ export class StatsPage extends LitElement { @state() globalFeatureSupportChartDataObj: WebStatusDataObj | undefined; + @state() + missingOneImplementationMap = new Map< + string, + Array + >(); + + @state() + missingOneImplementationChartDataObj: WebStatusDataObj | undefined; + static get styles(): CSSResultGroup { return [ SHARED_STYLES, @@ -101,7 +110,7 @@ export class StatsPage extends LitElement { ) as Array; // Build the list of values of checked menu-items. - this.globalFeatureSupportBrowsers = menuItemsArray + this.supportedBrowsers = menuItemsArray .filter(menuItem => menuItem.checked) .map(menuItem => menuItem.value) as BrowsersParameter[]; // Regenerate data and redraw. We should instead just filter it. @@ -121,6 +130,8 @@ export class StatsPage extends LitElement { globalFeatureSupportResizeObserver: ResizeObserver | null = null; + missingOneImplementationResizeObserver: ResizeObserver | null = null; + setupResizeObserver() { // Set up ResizeObserver one time to redraw chart when container resizes. if (!this.globalFeatureSupportResizeObserver) { @@ -133,6 +144,17 @@ export class StatsPage extends LitElement { }); this.globalFeatureSupportResizeObserver.observe(gfsChartElement); } + + if (!this.missingOneImplementationResizeObserver) { + const gfsChartElement = this.shadowRoot!.getElementById( + 'missing-one-implementation-chart', + ); + if (!gfsChartElement) return; + this.missingOneImplementationResizeObserver = new ResizeObserver(() => { + // TODO: trigger update based on resize. + }); + this.missingOneImplementationResizeObserver.observe(gfsChartElement); + } } async _fetchGlobalFeatureSupportData( @@ -149,18 +171,46 @@ export class StatsPage extends LitElement { )) { // Append the new data to existing data const existingData = - this.globalFeatureSupport.get(globalFeatureSupportKey(browser)) || []; - this.globalFeatureSupport.set(globalFeatureSupportKey(browser), [ + this.globalFeatureSupport.get(statsDataKey(browser)) || []; + this.globalFeatureSupport.set(statsDataKey(browser), [ ...existingData, ...page, ]); } - this.globalFeatureSupportChartDataObj = - this.createGlobalFeatureSupportDataFromMap(); + this.globalFeatureSupportChartDataObj = this.createDisplayDataFromMap( + this.globalFeatureSupport, + true, + ); }); await Promise.all(promises); // Wait for all browsers to finish } + // TODO: Finish this method with real data. + async _fetchMissingOneImplemenationCounts() { + const browserReleaseFeatureMetric: BrowserReleaseFeatureMetric = { + count: 8, + timestamp: new Date(Date.now() - 200 * 24 * 60 * 60 * 1000).toISOString(), + }; + const browserReleaseFeatureMetric1: BrowserReleaseFeatureMetric = { + count: 5, + timestamp: new Date(Date.now() - 150 * 24 * 60 * 60 * 1000).toISOString(), + }; + let count: number = 0; + ALL_BROWSERS.map(browser => { + browserReleaseFeatureMetric.count = 8 + count; + browserReleaseFeatureMetric1.count = 5 + count; + count++; + this.missingOneImplementationMap.set(statsDataKey(browser), [ + {...browserReleaseFeatureMetric}, + {...browserReleaseFeatureMetric1}, + ]); + }); + this.missingOneImplementationChartDataObj = this.createDisplayDataFromMap( + this.missingOneImplementationMap, + false, + ); + } + constructor() { super(); @@ -181,31 +231,35 @@ export class StatsPage extends LitElement { startDate, endDate, ); + await this._fetchMissingOneImplemenationCounts(); return this.globalFeatureSupport; }, }); } - // Make a DataTable from the data in globalFeatureSupport - createGlobalFeatureSupportDataFromMap(): WebStatusDataObj { - // Get the list of browsers from globalFeatureSupport - const browsers = this.globalFeatureSupportBrowsers; + // Make a DataTable from the target data map. + createDisplayDataFromMap( + targetMap: Map>, + addMax: boolean, + ): WebStatusDataObj { + // Get the list of supported browsers. + const browsers = this.supportedBrowsers; const dataObj: WebStatusDataObj = {cols: [], rows: []}; dataObj.cols.push({type: 'date', label: 'Date', role: 'domain'}); for (const browser of browsers) { dataObj.cols.push({type: 'number', label: browser, role: 'data'}); } - dataObj.cols.push({type: 'number', label: 'Max features', role: 'data'}); + if (addMax) { + dataObj.cols.push({type: 'number', label: 'Max features', role: 'data'}); + } // Map from date to an object with counts for each browser const dateToBrowserDataMap = new Map(); // Merge data across all browsers into one array of rows. for (const browser of browsers) { - const data = this.globalFeatureSupport.get( - globalFeatureSupportKey(browser), - ); + const data = targetMap.get(statsDataKey(browser)); if (!data) continue; for (const row of data) { if (!row) continue; @@ -218,36 +272,42 @@ export class StatsPage extends LitElement { browserCounts[browser] = featureCount; } } - // Create array of dateToBrowserDataMap entries and sort by dateSeconds const data = Array.from(dateToBrowserDataMap.entries()).sort( ([d1], [d2]) => d1 - d2, ); // For each date, add a row to the dataTable - // Accumulate the max count across all browsers. - let max = 0; for (const datum of data) { const dateSeconds = datum[0]; const date = new Date(dateSeconds); const browserCounts = datum[1]; // Make an array of browser counts, in the order of browsers. // If the browser is not in the browserCounts, add null. - const browserCountArray = browsers.map(browser => { - if (browserCounts[browser]) { - max = Math.max(max, browserCounts[browser]); - return browserCounts[browser]; + const browserCountArray = browsers.map( + browser => browserCounts[browser] || null, + ); + + if (addMax) { + let maxCount = 0; + for (const count of browserCountArray) { + if (count) { + maxCount = Math.max(maxCount, count); + } } - return null; - }); - dataObj.rows.push([date, ...browserCountArray, max]); + dataObj.rows.push([date, ...browserCountArray, maxCount]); + } else { + dataObj.rows.push([date, ...browserCountArray]); + } } return dataObj; } - generateGlobalFeatureSupportChartOptions(): google.visualization.LineChartOptions { + generatedisplayDataChartOptions( + vAxisTitle: string, + ): google.visualization.LineChartOptions { // Compute seriesColors from selected browsers and BROWSER_ID_TO_COLOR - const selectedBrowsers = this.globalFeatureSupportBrowsers; + const selectedBrowsers = this.supportedBrowsers; const seriesColors = [...selectedBrowsers, 'total'].map(browser => { const browserKey = browser as keyof typeof BROWSER_ID_TO_COLOR; return BROWSER_ID_TO_COLOR[browserKey]; @@ -264,7 +324,7 @@ export class StatsPage extends LitElement { }, vAxis: { minValue: 0, - title: 'Number of features supported', + title: vAxisTitle, format: '#,###', }, legend: {position: 'top'}, @@ -331,10 +391,13 @@ export class StatsPage extends LitElement { return html` Loading chart... @@ -350,6 +413,32 @@ export class StatsPage extends LitElement { }); } + renderMissingOneImplementationChartWhenComplete(): TemplateResult { + return html` + + Loading chart... + + `; + } + + renderMissingOneImplementationChart(): TemplateResult | undefined { + return this._loadingGFSTask.render({ + complete: () => this.renderMissingOneImplementationChartWhenComplete(), + error: () => this.renderChartWhenError(), + initial: () => this.renderChartWhenInitial(), + pending: () => this.renderChartWhenPending(), + }); + } + renderGlobalFeatureSupport(): TemplateResult { return html` @@ -364,7 +453,7 @@ export class StatsPage extends LitElement { id="global-feature-support-browser-selector" multiple stay-open-on-select - .value="${this.globalFeatureSupportBrowsers.join(' ')}" + .value="${this.supportedBrowsers.join(' ')}" > @@ -402,9 +491,7 @@ export class StatsPage extends LitElement { Safari -
- Chart goes here... -
+
${this.renderMissingOneImplementationChart()}
`; }