Class: Sentiero::Analytics::ScrollCollector

Inherits:
Object
  • Object
show all
Includes:
Bounded, Events, Stats
Defined in:
lib/sentiero/analytics/collectors/scroll_collector.rb

Overview

Per-URL scroll depth across page segments and windows.

rrweb Metas carry the viewport height but NOT the document height, so page height is ESTIMATED as the deepest (max scroll + viewport) any sample reached — exact when somebody read to the end, a lower bound otherwise. Viewport-less samples fall back to pixels (no percentage derivable).

Per window: #observe each segment, then #flush_window once to commit each URL's deepest segment as ONE sample.

Constant Summary collapse

DISTRIBUTION_BINS =
%w[0-25 25-50 50-75 75-100].freeze

Constants included from Events

Events::CUSTOM, Events::INCREMENTAL, Events::META, Events::SOURCE_INPUT, Events::SOURCE_MOUSE_INTERACTION, Events::SOURCE_SCROLL

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Bounded

#bounded_fetch, #bounded_increment

Methods included from Stats

#mean, #offset_ms, #percentile, #top_counts

Constructor Details

#initialize(max_urls: nil) ⇒ ScrollCollector

max_urls: nil unbounded; an Integer caps distinct URLs, flipping #capped.



28
29
30
31
32
33
# File 'lib/sentiero/analytics/collectors/scroll_collector.rb', line 28

def initialize(max_urls: nil)
  @max_urls = max_urls
  @samples_by_url = {} # url => [{max_y:, viewport_height:}, ...]
  @window = {} # url => deepest segment depth in the current window
  @capped = false
end

Instance Attribute Details

#cappedObject (readonly)

Returns the value of attribute capped.



25
26
27
# File 'lib/sentiero/analytics/collectors/scroll_collector.rb', line 25

def capped
  @capped
end

Instance Method Details

#flush_windowObject

One sample per (url, window): the deepest of the window's segments, then resets.



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/sentiero/analytics/collectors/scroll_collector.rb', line 45

def flush_window
  @window.each do |url, depth|
    samples = bounded_fetch(@samples_by_url, url, @max_urls) { [] }
    if samples.nil?
      @capped = true
      next
    end
    samples << depth
  end
  @window = {}
end

#observe(url, segment) ⇒ Object

Deepest segment per url wins; segments with no scroll are ignored.



36
37
38
39
40
41
42
# File 'lib/sentiero/analytics/collectors/scroll_collector.rb', line 36

def observe(url, segment)
  depth = segment_depth(segment)
  return unless depth

  current = @window[url]
  @window[url] = depth if current.nil? || depth[:max_y] > current[:max_y]
end

#pagesObject



65
66
67
# File 'lib/sentiero/analytics/collectors/scroll_collector.rb', line 65

def pages
  @samples_by_url.transform_values { |samples| summarize_samples(samples) }
end

#summarize(url) ⇒ Object

nil when nothing was recorded for the URL.



58
59
60
61
62
63
# File 'lib/sentiero/analytics/collectors/scroll_collector.rb', line 58

def summarize(url)
  samples = @samples_by_url[url]
  return nil unless samples && !samples.empty?

  summarize_samples(samples)
end