Modul:Vremenski okvir/Dijagram
Izgled
Dokumentaciju za ovaj modul možete napraviti na stranici Modul:Vremenski okvir/Dijagram/dok
--
-- VREMENSKI OKVIR - DIJAGRAM
--
w = {};
math_mod = require('Module:Math');
local months = {"jan", "feb", "mar", "apr", "maj", "jun",
"jul", "aug", "sep", "okt", "nov", "dec"}
local max_height = 200
local d_args = {
hide = 'sakrij',
collapsed = 'sklopi',
label = 'Temperatura u °C • padavine u mm',
diagram = 'Dijagram:',
temperature = 'Temperatura',
precipitation = 'Padavine'
}
-- Lets the user use ',' instead of '.' i.e. 290,9 (290.9 works too).
local function convertToNumbers(table_arg)
local hi_val = 1
local map = {}
for i,val in pairs(table_arg) do
if val == nil then
map[i] = nil
else
local to_dot = mw.ustring.gsub(val, ",", ".")
local to_no = math_mod._cleanNumber(to_dot)
map[i] = to_no
end
end
return map
end
-- Get min value if min value is lesser than 0.
local function getMinFromTable(table_arg)
local min_val = 0 -- the min_val should at least be 0
for i,val in pairs(table_arg) do
if val ~= nil then
if val < min_val then
min_val = val
end
end
end
return min_val
end
-- Get max value if max is greater than 1.
local function getMaxFromTable(table_arg)
local max_val = 1
for i,val in pairs(table_arg) do
if val ~= nil then
if val > max_val then
max_val = val
end
end
end
return max_val
end
-- Renders a bar for the chart
-- the bar_info parameter is a table with keys:
-- height, bottom, horizontal_axis, above_label and below_label.
local function renderBar(html_root, bar_info)
if bar_info == nil then
return
end
local div = html_root:tag('div')
:css('position', 'relative')
:css('z-index', '100')
:css('margin', 'auto')
:css('width', '17px')
:css('height', '216px')
:css('padding', '1px')
-- add a horizontal axis
if bar_info.horizontal_axis ~= nil then
local zero_pos_px_str = math_mod._round(bar_info.horizontal_axis, 1) .. 'px'
div:tag('div')
:css('position', 'absolute')
:css('z-index', '2')
:css('bottom', zero_pos_px_str)
:css('width', '17px')
:css('border-bottom', '1px dotted #A9A9A9')
end
-- add bar
local height_str = math_mod._round(bar_info.height, 1) .. 'px'
local bottom_str = math_mod._round(bar_info.bottom, 1) .. 'px'
local bar = div:tag('div')
:css('position', 'absolute')
:css('z-index', '1')
:css('left', '2px')
:css('bottom', bottom_str)
:css('width', '15px')
:css('height', height_str)
:css('overflow', 'hidden')
:css('background', '#8AB0FF')
-- Prepare bar label above, note: '+3' extra space for border-top.
local label_map = {{
bottom = math_mod._round(bar_info.height+bar_info.bottom+3, 1) .. 'px',
label = bar_info.above_label
}}
-- Prepare bar label below if necessary.
if bar_info.below_label ~= nil then
table.insert(label_map, {
bottom = math_mod._round(bar_info.bottom-16, 1) .. 'px',
label = bar_info.below_label
})
-- Change css-style (-> we assume the bar is for temperature)
-- these borders affects the height of the bar,
-- if removed: change the height ('-4') in function
-- renderTemperatureDiagram and remove '+3' in label_map.bottom for
-- above label.
bar:css('background', '#e8e8e8')
:css('border-top', '2px solid red')
:css('border-bottom', '2px solid blue')
end
-- Add bar labels (above and below).
for i,v in ipairs(label_map) do
div:tag('div')
:css('position', 'absolute')
:css('z-index', '4')
:css('bottom', v.bottom)
:css('width', '17px')
:css('text-align', 'center')
:css('font-size', '90%')
:wikitext((mw.ustring.gsub( (mw.ustring.gsub( v.label, "%-", "−") ), "%.", ",") ))
end
end
local function renderTemperatureDiagram(html_root, table_min, table_max)
html_root:tag('tr')
:tag('td')
:attr('colspan', '13')
:css('background', '#eee')
:css('text-align', 'center')
:css('font-weight', 'bold')
:wikitext(d_args.temperature)
local f_tr = html_root:tag('tr')
:css('vertical-align', 'bottom')
-- offset, border-left
f_tr:tag('td')
:css('border-left', '1px solid #A9A9A9')
:css('border-bottom', '1px solid #A9A9A9')
local min_map = convertToNumbers(table_min)
local max_map = convertToNumbers(table_max)
local min_val = getMinFromTable(min_map)
local max_val = getMaxFromTable(max_map)
local offset = 16
local zero_pos = 0
if min_val < 0 then
zero_pos = min_val*(-1)
end
-- generate rows
for i,v in ipairs(months) do
-- check values
if min_map[tostring(v)] ~= nil and max_map[tostring(v)] ~= nil then
-- check max and min value
if min_map[tostring(v)] > max_map[tostring(v)] then
-- this should not happen -> store nil everywhere
min_map[tostring(v)] = nil
max_map[tostring(v)] = nil
end
end
local column = f_tr:tag('td')
:css('border-bottom', '1px solid #A9A9A9')
local bar_info = nil
if min_map[tostring(v)] ~= nil and max_map[tostring(v)] ~= nil then
-- calculate height
local bar_height = ((max_height-offset) / (max_val-min_val)
* (max_map[tostring(v)] - min_map[tostring(v)]))
-- Remove some px from height
-- (from bar-style:border-top/-bottom in renderBar,
-- see function renderBar for more info).
if bar_height > 4 then
bar_height = bar_height-4
else
bar_height = 0
end
bar_info = {
height = bar_height,
bottom = ((max_height-offset) / (max_val-min_val)
* (zero_pos+min_map[tostring(v)])) + offset,
horizontal_axis = (max_height-offset) / (max_val-min_val)
* zero_pos + offset,
above_label = table_max[tostring(v)],
below_label = table_min[tostring(v)]
}
end
renderBar(column, bar_info)
end
end
local function renderPrecipitationDiagram(html_root, table_arg)
html_root:tag('tr')
:tag('td')
:attr('colspan', '13')
:css('background', '#eee')
:css('text-align', 'center')
:css('font-weight', 'bold')
:wikitext(d_args.precipitation)
local f_tr = html_root:tag('tr')
:css('vertical-align', 'bottom')
-- offset, border-left
f_tr:tag('td')
:css('border-left', '1px solid #A9A9A9')
:css('border-bottom', '1px solid #A9A9A9')
-- convert to numbers and get the highest value
local number_map = convertToNumbers(table_arg)
local max_val = getMaxFromTable(number_map)
-- generate rows
for i,v in ipairs(months) do
local column = f_tr:tag('td')
:css('border-bottom', '1px solid #A9A9A9')
local bar_info = nil
if number_map[tostring(v)] ~= nil then
bar_info = {
height = max_height / max_val * number_map[tostring(v)],
bottom = 0,
above_label = number_map[tostring(v)]
}
end
renderBar(column, bar_info)
end
end
local function renderBarDiagram(html_root, width, colspan, args)
local bd_table = html_root:tag('td')
:css('width', width)
:attr('colspan', colspan)
:tag('table')
:attr('border', '0')
:attr('cellspacing', '0')
:attr('cellpadding', '0')
:attr('align', 'left')
:css('width', '100%')
:css('font-size', '75%')
:css('background', '#f8f8f8')
:css('text-align', 'center')
local n = 0
for _ in pairs(args) do n = n + 1 end
if n == 1 then
renderPrecipitationDiagram(bd_table, args[1])
elseif n == 2 then
renderTemperatureDiagram(bd_table, args[1], args[2])
end
-- Render months along x-axis.
local m_tr = bd_table:tag('tr')
:css('background', '#FFFFFF')
m_tr:tag('td') -- offset
for i,v in ipairs(months) do
m_tr:tag('td')
:css('text-align', 'center')
:wikitext(tostring(v))
end
end
local function _diagram(table_args)
-- (table) root
local root = mw.html.create():tag('table')
:addClass('mw-collapsible')
:attr('cellspacing', '0')
:css('background', 'transparent')
:css('width', '100%')
if table_args.state == d_args.hide or
table_args.state == d_args.collapsed then
root:addClass('mw-collapsed')
end
local header = root:tag('tr')
:css('font-size', '85%')
header:tag('td')
:css('padding', '0')
:wikitext(d_args.label)
header:tag('th')
:css('padding', '0')
:css('font-weight', 'normal')
:css('text-align', 'right')
:wikitext(d_args.diagram)
-- set diagram frame width
local diagram_frame_width = '50%'
local diagram_frame_colspan = '1'
if tableIsEmpty(table_args.minTemperature) or tableIsEmpty(table_args.maxTemperature)
or tableIsEmpty(table_args.precipitation) then
diagram_frame_width = '100%'
diagram_frame_colspan = '2'
end
local tr = root:tag('tr')
local bd_args = nil
if not tableIsEmpty(table_args.minTemperature)
and not tableIsEmpty(table_args.maxTemperature) then
bd_args = { table_args.minTemperature, table_args.maxTemperature }
renderBarDiagram(tr, diagram_frame_width, diagram_frame_colspan, bd_args)
end
if not tableIsEmpty(table_args.precipitation) then
bd_args = { table_args.precipitation }
renderBarDiagram(tr, diagram_frame_width, diagram_frame_colspan, bd_args)
end
return tostring(root)
end
function tableIsEmpty(t)
if t == nil then
return true
end
for _, _ in pairs(t) do
return false
end
return true
end
function w.diagram(frame)
if tableIsEmpty(frame) then
return
end
return _diagram(frame)
end
return w