diff --git a/explorer/Explorer.tsx b/explorer/Explorer.tsx index d9106ebad4..952d9f3ef2 100644 --- a/explorer/Explorer.tsx +++ b/explorer/Explorer.tsx @@ -26,6 +26,7 @@ import { SlideShowController, SlideShowManager, DEFAULT_GRAPHER_ENTITY_TYPE, + GrapherAnalytics, } from "@ourworldindata/grapher" import { Bounds, @@ -188,6 +189,8 @@ export class Explorer EntityPickerManager, GrapherManager { + analytics = new GrapherAnalytics() + // caution: do a ctrl+f to find untyped usages static renderSingleExplorerOnExplorerPage( program: ExplorerProps, @@ -271,6 +274,24 @@ export class Explorer return new Map(arr.map((config) => [config.id!, config])) } + private setUpIntersectionObserver(): void { + if (typeof window !== "undefined" && "IntersectionObserver" in window) { + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + this.analytics.logExplorerView( + this.explorerProgram.slug, + this.explorerProgram.decisionMatrix.currentParams + ) + observer.disconnect() + } + }) + }) + observer.observe(this.grapherContainerRef.current!) + this.disposers.push(() => observer.disconnect()) + } + } + disposers: (() => void)[] = [] componentDidMount() { this.setGrapher(this.grapherRef!.current!) @@ -290,6 +311,7 @@ export class Explorer this.grapher?.populateFromQueryParams(url.queryParams) exposeInstanceOnWindow(this, "explorer") + this.setUpIntersectionObserver() this.attachEventListeners() this.updateEntityPickerTable() // call for the first time to initialize EntityPicker } @@ -414,6 +436,11 @@ export class Explorer : tabsWithoutTable[0] ?? GrapherTabOption.table this.grapher.populateFromQueryParams(newGrapherParams) + + this.analytics.logExplorerView( + this.explorerProgram.slug, + this.explorerProgram.decisionMatrix.currentParams + ) } @action.bound private setGrapherTable(table: OwidTable) { diff --git a/packages/@ourworldindata/grapher/src/core/GrapherAnalytics.ts b/packages/@ourworldindata/grapher/src/core/GrapherAnalytics.ts index bbaf5234f4..8e84b2508b 100644 --- a/packages/@ourworldindata/grapher/src/core/GrapherAnalytics.ts +++ b/packages/@ourworldindata/grapher/src/core/GrapherAnalytics.ts @@ -15,6 +15,7 @@ export enum EventCategory { GrapherView = "owid.grapher_view", GrapherClick = "owid.grapher_click", GrapherError = "owid.grapher_error", + ExplorerView = "owid.explorer_view", ExplorerCountrySelector = "owid.explorer_country_selector", Hover = "owid.hover", KeyboardShortcut = "owid.keyboard_shortcut", @@ -50,6 +51,8 @@ interface GAEvent { eventTarget?: string grapherPath?: string grapherView?: string // specifies a view in a multi-dim data page + explorerPath?: string + explorerView?: string } // taken from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/de66435d18fbdb2684947d16b5cd3a77f876324c/types/gtag.js/index.d.ts#L151-L156 @@ -97,6 +100,14 @@ export class GrapherAnalytics { }) } + logExplorerView(slug: string, view: Record): void { + this.logToGA({ + event: EventCategory.ExplorerView, + explorerPath: `/explorers/${slug}`, + explorerView: JSON.stringify(view), + }) + } + logGlobalEntitySelector(action: entityControlEvent, note?: string): void { this.logToGA({ event: EventCategory.GlobalEntitySelectorUsage, @@ -194,6 +205,7 @@ export class GrapherAnalytics { } protected logToGA(event: GAEvent): void { + console.log("Analytics.logToGA", event) if (DEBUG && this.isDev) { // eslint-disable-next-line no-console console.log("Analytics.logToGA", event)