module Streams module Overlay # PNG 1280×720 trasparente: tabellone alto-sinistra, badge alto-destra, logo chiaro (logo-white-m) basso-destra. class SvgBuilder CANVAS_W = 1280 CANVAS_H = 720 def initialize(session, badge:) @session = session @match = session.match @team = @match.team @score = session.score_state @badge = badge end def to_svg cols = score_columns <<~SVG #{scorebug_svg(cols)} #{badge_svg} #{brand_watermark_svg} SVG end private def score_columns score = @score unless score return { labels: ["1"], home: ["0"], away: ["0"], home_name: abbrev(@match.team.name), away_name: abbrev(@match.opponent_name), sets_won: "0-0", current_set: 1 } end partials = Array(score.set_partials) labels = partials.map { |p| p["set"].to_s } home = partials.map { |p| p["home"].to_s } away = partials.map { |p| p["away"].to_s } labels << score.current_set.to_s home << score.home_points.to_s away << score.away_points.to_s { labels: labels, home: home, away: away, home_name: abbrev(@match.team.name), away_name: abbrev(@match.opponent_name), sets_won: "#{score.home_sets}-#{score.away_sets}", current_set: score.current_set } end def scorebug_svg(cols) x0 = 12 y0 = 12 col_w = 26 team_w = 118 row_h = 18 head_h = 16 pad = 8 n = cols[:labels].length box_w = team_w + n * col_w + pad * 2 box_h = head_h + row_h * 2 + 22 + pad * 2 live_i = n - 1 home_primary = @team.effective_primary_color away_primary = Overlay.badge_away_color(@team) header_cells = cols[:labels].map.with_index do |label, i| cx = x0 + pad + team_w + i * col_w + col_w / 2 "#{escape(label)}" end.join home_pts = cols[:home].map.with_index do |val, i| cx = x0 + pad + team_w + i * col_w + col_w / 2 y = y0 + pad + head_h + 14 fill = i == live_i ? home_primary : "#111111" weight = i == live_i ? "900" : "800" bg = i == live_i ? "" : "" "#{bg}#{escape(val)}" end.join away_pts = cols[:away].map.with_index do |val, i| cx = x0 + pad + team_w + i * col_w + col_w / 2 y = y0 + pad + head_h + row_h + 14 fill = i == live_i ? away_primary : "#111111" weight = i == live_i ? "900" : "800" bg = i == live_i ? "" : "" "#{bg}#{escape(val)}" end.join <<~SVG #{header_cells} #{escape(cols[:home_name])} #{home_pts} #{escape(cols[:away_name])} #{away_pts} MATCH LIVE TV SVG end def brand_watermark_svg path = Overlay.brand_logo_path return "" unless path.file? w = 108 h = 108 x = CANVAS_W - 14 - w y = CANVAS_H - 14 - h uri = "file://#{path.expand_path}" <<~SVG SVG end def badge_svg text = @badge.text bg = @badge.background fg = @badge.foreground pad_x = 12 pad_y = 6 fs = 11 tw = text.length * 6.5 + pad_x * 2 th = fs + pad_y * 2 x = CANVAS_W - 12 - tw y = 12 <<~SVG #{escape(text)} SVG end def abbrev(name, max = 16) n = name.to_s n.length <= max ? n : "#{n[0, max - 1]}…" end def escape(str) str.to_s.gsub("&", "&").gsub("<", "<").gsub(">", ">").gsub('"', """) end end end end