Documentation for this module may be created at Module:Television Rotten Tomatoes scores/doc
-- This module implements {{Television Rotten Tomatoes scores}}.
--------------------------------------------------------------------------------
-- TVRT class
-- The main class.
--------------------------------------------------------------------------------
local TVRT = {}
function TVRT.upper(str)
return (str:gsub("^%l", string.upper))
end
function TVRT.round(value)
return math.floor(value + 0.5)
end
-- Create the graph and table
function TVRT.new(frame,args)
args = args or {}
-- Variables
local timeline = ""
local episodes = 0
local graph_width = args.width and tonumber(args.width) or 600
local graph_height = args.height and tonumber(args.height) or 300
local force_gap = args.forcegap or nil
-- Create table and top caption
local roottable = mw.html.create('table')
roottable
:addClass('wikitable')
:addClass(args.align and 'float'..args.align or '')
:css('text-align', 'center')
:css('width', (args.width or 600)..'px')
:tag('caption'):wikitext('<i>'..(args.title or '')..'</i>'..(args.label and ' '..string.lower(args.label) or '')..': Critical reception by episode')
local rootcell = roottable:tag('tr'):tag('td')
-- Border widths
local g_l = 50
local g_r = 50
local g_t = 30
local g_b = 40
local g_lr_border = g_l + g_r
local g_tb_border = g_t + g_b
local score_min = 100
local score_max = 0
-- Number of episodes
for k,v in pairs(args) do
if (string.lower(v) == 'n/a') or (not string.match(k,'[^%d]+') and not string.match(v,'[^%d%.]+')) then
episodes = episodes + 1
if v ~= "" and v ~= nil then
score_min = math.min(score_min, tonumber(v))
score_max = math.max(score_max, tonumber(v))
end
end
end
-- Position varibles for each entry
local old_x = g_l
local old_y = 0
local new_x = old_x
local new_y = old_y
local increment_x = TVRT.round((graph_width-g_lr_border)/(episodes-1))
local period_min = 0
local period_max = 100
if args.minimize_y then
period_min = math.floor(score_min/10)*10
period_max = math.ceil(score_max/10)*10
end
-- One percentage on the y axis is this many pixels
local percent_pixel = (graph_height-g_tb_border)/(period_max-period_min)
-- Create the timeline
timeline = timeline .. "\nImageSize = width:"..graph_width.." height:"..graph_height.."\n"
timeline = timeline .. "\nPlotArea = left:"..g_l.." bottom:"..g_b.." top:"..g_t.." right:"..g_r.."\n"
timeline = timeline .. "\nTimeAxis = orientation:vertical format:y\n"
timeline = timeline .. "\nAlignBars = justify\n"
timeline = timeline .. "\nColors =\n"
timeline = timeline .. "\n id:grayH value:gray(0.95)\n"
timeline = timeline .. "\n id:grayV value:gray(0.85)\n"
-- Colour from hex to 0-1 RGB
local hex = args["color"]:gsub("#","")
if #hex == 3 then
hex = hex:sub(1,1) .. hex:sub(1,1) .. hex:sub(2,2) .. hex:sub(2,2) .. hex:sub(3,3) .. hex:sub(3,3) -- If it's 3 hex chars then make it six instead
end
rgbR = tonumber("0x"..hex:sub(1,2))/256
rgbG = tonumber("0x"..hex:sub(3,4))/256
rgbB = tonumber("0x"..hex:sub(5,6))/256
timeline = timeline .. "\n id:graph value:rgb("..rgbR..", "..rgbG..", "..rgbB..")\n"
-- Further the timeline
timeline = timeline .. "\nPeriod = from:"..period_min.." till:"..period_max.."\n"
timeline = timeline .. "\nScaleMajor = unit:year start:"..period_min.." increment:10\n"
timeline = timeline .. "\nScaleMinor = unit:year start:"..period_min.." increment:2\n"
-- X-axis position for each entry
timeline = timeline .. "\nBarData=\n"
for episode = 1,episodes do
timeline = timeline .. "\n bar:"..episode.." text:"..episode.."\n"
end
-- Faint line at each 10% on the y-axis
timeline = timeline .. "\nLineData=\n"
timeline = timeline .. "\n layer:front\n"
for variance = period_min,period_max,10 do
timeline = timeline .. "\n at:"..variance.." frompos:"..old_x.." tillpos:"..(graph_width-g_r).." color:grayH width:1 layer:back\n"
end
-- Draw the lines between each entry
local all_positions = {}
local last_x = nil
local last_y = nil
local current_x = g_l
for episode = 1, episodes do
local score = tonumber(args[episode])
if score then
local y = TVRT.round(g_b + (score-period_min) * percent_pixel)
if last_x then
timeline = timeline .. "\n points:("..last_x..","..last_y..")("..current_x..","..y..") color:graph width:1.5\n"
end
-- Draw square marker
timeline = timeline .. "\n at:"..score.." frompos:"..(current_x-2).." tillpos:"..(current_x+2).." color:graph width:4\n"
all_positions[#all_positions+1] = {x = current_x, y = y, episode = episode}
last_x = current_x
last_y = y
elseif force_gap then
last_x = nil
last_y = nil
end
current_x = current_x + increment_x
end
-- Dud entry to allow positioning of final value
all_positions[#all_positions+1] = {x = 1000, y = 1000, episode = nil}
-- Draw the values on the graph
local fontsize = 8
local old_slope = 0
local new_slope = old_slope
timeline = timeline .. "\nTextData=\n"
timeline = timeline .. "\n pos:("..(graph_width/2-20)..",15) fontsize:S text:Episode\n"
timeline = timeline .. "\n pos:(20,"..(graph_height-15)..") fontsize:S text:Percent\n"
for k,v in pairs(all_positions) do
-- Determine the position of the text based on the slope of each line
local nextv = all_positions[k+1]
if nextv ~= nil then
new_slope = (nextv.y-v.y) / (nextv.x-v.x)
if new_slope > 0 then
v.y = v.y - fontsize*1.5
else
v.y = v.y + fontsize*0.5
end
old_slope = new_slope
end
local label = v.episode and args[v.episode] or ""
timeline = timeline .. "\n pos:("..v.x..","..v.y..") textcolor:black fontsize:"..fontsize.." text:"..label.."\n"
end
-- Add the timeline itself to the base table
local timeline_base = frame:preprocess("<timeline>" .. timeline .. "</timeline>")
rootcell:node(timeline_base)
rootcell:tag('div'):css('clear','both')
-- Create bottom caption
local lower_caption_text1 = (args.label and TVRT.upper(string.lower(args.label)) or "<i>"..args.title.."</i>") .. " (" .. (args.year or "Year?") .. "): "
local lower_caption_text2 = "Percentage of positive critics' reviews tracked by the website [[Rotten Tomatoes]]" .. (args.ref or "Ref?")
local lower_caption1 = mw.html.create('span')
local lower_caption2 = mw.html.create('span')
lower_caption1
:css('color', '#'..hex)
:css('font-weight', 'bold')
:wikitext(lower_caption_text1)
lower_caption2
:wikitext(lower_caption_text2)
if not args.nolower then rootcell:node(lower_caption1) end
rootcell:node(lower_caption2)
return roottable
end
--------------------------------------------------------------------------------
-- Exports
--------------------------------------------------------------------------------
local p = {}
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
removeBlanks = false,
wrappers = 'Template:Television Rotten Tomatoes scores'
})
return TVRT.new(frame,args)
end
return p