模块:Weather box:修订间差异
来自Blockland Wiki
更多操作
无编辑摘要 标签:手工回退 |
无编辑摘要 |
||
| 第74行: | 第74行: | ||
-- ========================================================================= | -- ========================================================================= | ||
-- | -- 图表核心计算与现代化渲染 | ||
-- ========================================================================= | -- ========================================================================= | ||
local function calculateKoppen(temps, precips) | local function calculateKoppen(temps, precips) | ||
| 第100行: | 第100行: | ||
local function makeGraph(frame, args) | local function makeGraph(frame, args) | ||
local months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} | local months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} | ||
local month_labels = {"1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"} | |||
local d = { high = {}, mean = {}, low = {}, rain = {} } | local d = { high = {}, mean = {}, low = {}, rain = {} } | ||
local max_t, max_p = | local max_t, min_t, max_p = -999, 999, 0 | ||
for i, m in ipairs(months) do | for i, m in ipairs(months) do | ||
| 第110行: | 第111行: | ||
if d.high[i] > max_t then max_t = d.high[i] end | if d.high[i] > max_t then max_t = d.high[i] end | ||
if d.low[i] < min_t then min_t = d.low[i] end | |||
if d.rain[i] > max_p then max_p = d.rain[i] end | if d.rain[i] > max_p then max_p = d.rain[i] end | ||
end | end | ||
max_t = math.ceil(max_t / 10) * 10 | -- 动态计算刻度范围 | ||
max_p = math.ceil(max_p / | max_t = math.ceil((max_t + 5) / 10) * 10 | ||
min_t = math.floor((min_t - 5) / 10) * 10 | |||
if min_t > 0 then min_t = 0 end | |||
max_p = math.ceil(max_p / 50) * 50 | |||
if max_p == 0 then max_p = 100 end | |||
local w, h = | local w, h = 600, 350 | ||
local padding = { t = | local padding = { t = 50, b = 40, l = 50, r = 50 } | ||
local chart_w, chart_h = w - padding.l - padding.r, h - padding.t - padding.b | local chart_w, chart_h = w - padding.l - padding.r, h - padding.t - padding.b | ||
local function ty(v) return h - padding.b - (v / max_t * chart_h) end | local function ty(v) return h - padding.b - ((v - min_t) / (max_t - min_t) * chart_h) end | ||
local function py(v) return h - padding.b - (v / max_p * chart_h) end | local function py(v) return h - padding.b - (v / max_p * chart_h) end | ||
local function tx(i) return padding.l + (i - 0.5) * (chart_w / 12) end | local function tx(i) return padding.l + (i - 0.5) * (chart_w / 12) end | ||
local svg = string.format('<svg width="100%%" viewBox="0 0 %d %d" style="background:# | local svg = string.format('<svg width="100%%" viewBox="0 0 %d %d" style="background:#ffffff; font-family:-apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Helvetica, Arial, sans-serif; display:block;">', w, h) | ||
for v = | -- 图例 (Legend) | ||
svg = svg .. '<g font-size="12" fill="#4B5563">' | |||
svg = svg .. '<rect x="' .. (w/2 - 140) .. '" y="15" width="12" height="12" rx="2" fill="#60A5FA" opacity="0.4"/>' | |||
svg = svg .. '<text x="' .. (w/2 - 122) .. '" y="26">降水量</text>' | |||
svg = svg .. '<line x1="' .. (w/2 - 60) .. '" y1="21" x2="' .. (w/2 - 35) .. '" y2="21" stroke="#EF4444" stroke-width="2" stroke-linecap="round"/>' | |||
svg = svg .. '<circle cx="' .. (w/2 - 47.5) .. '" cy="21" r="3" fill="#EF4444"/>' | |||
svg = svg .. '<text x="' .. (w/2 - 27) .. '" y="26">高温</text>' | |||
svg = svg .. '<line x1="' .. (w/2 + 15) .. '" y1="21" x2="' .. (w/2 + 40) .. '" y2="21" stroke="#F59E0B" stroke-width="2" stroke-linecap="round"/>' | |||
svg = svg .. '<circle cx="' .. (w/2 + 27.5) .. '" cy="21" r="3" fill="#F59E0B"/>' | |||
svg = svg .. '<text x="' .. (w/2 + 48) .. '" y="26">均温</text>' | |||
svg = svg .. '<line x1="' .. (w/2 + 90) .. '" y1="21" x2="' .. (w/2 + 115) .. '" y2="21" stroke="#3B82F6" stroke-width="2" stroke-linecap="round"/>' | |||
svg = svg .. '<circle cx="' .. (w/2 + 102.5) .. '" cy="21" r="3" fill="#3B82F6"/>' | |||
svg = svg .. '<text x="' .. (w/2 + 123) .. '" y="26">低温</text>' | |||
svg = svg .. '</g>' | |||
-- 绘制网格与 Y轴刻度 (左侧温度,右侧降水) | |||
local t_step = 10 | |||
for v = min_t, max_t, t_step do | |||
local y = ty(v) | local y = ty(v) | ||
svg = svg .. string.format('<line x1="%d" y1="% | if y >= padding.t and y <= h - padding.b then | ||
-- 虚线网格 | |||
local stroke_color = (v == 0) and "#9CA3AF" or "#F3F4F6" | |||
local stroke_width = (v == 0) and "1.5" or "1" | |||
local dash = (v == 0) and "" or 'stroke-dasharray="4 4"' | |||
svg = svg .. string.format('<line x1="%d" y1="%f" x2="%d" y2="%f" stroke="%s" stroke-width="%s" %s />', padding.l, y, w - padding.r, y, stroke_color, stroke_width, dash) | |||
-- 左侧温度标签 | |||
svg = svg .. string.format('<text x="%d" y="%f" font-size="11" fill="#6B7280" text-anchor="end" alignment-baseline="middle">%d°C</text>', padding.l - 8, y, v) | |||
end | |||
end | |||
local p_step = max_p / 5 | |||
for v = 0, max_p, p_step do | |||
local y = py(v) | |||
if y >= padding.t and y <= h - padding.b then | |||
-- 右侧降水标签 | |||
svg = svg .. string.format('<text x="%d" y="%f" font-size="11" fill="#9CA3AF" text-anchor="start" alignment-baseline="middle">%d mm</text>', w - padding.r + 8, y, math.floor(v)) | |||
end | |||
end | end | ||
-- 柱状图 (降水) | |||
local bar_w = (chart_w / 12) * 0.5 | |||
for i, p_val in ipairs(d.rain) do | for i, p_val in ipairs(d.rain) do | ||
local bh = (p_val / max_p * chart_h) | local bh = (p_val / max_p * chart_h) | ||
svg = svg .. string.format('<rect x="%f" y="%f" width="%f" height="%f" fill="# | local y = py(p_val) | ||
svg = svg .. string.format('<rect x="%f" y="%f" width="%f" height="%f" fill="#60A5FA" opacity="0.35" rx="2"><title>%s 降水量: %s mm</title></rect>', tx(i) - bar_w/2, y, bar_w, bh, month_labels[i], tostring(p_val)) | |||
end | end | ||
local function drawLine(data, color, | -- 辅助函数:绘制平滑视觉的折线与数据点 | ||
local function drawLine(data, color, name) | |||
local pts = "" | local pts = "" | ||
for i, v in ipairs(data) do pts = pts .. string.format("%f,%f ", tx(i), ty(v)) end | for i, v in ipairs(data) do pts = pts .. string.format("%f,%f ", tx(i), ty(v)) end | ||
local line_svg = string.format('<polyline points="%s" fill="none" stroke="%s" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round" />', pts, color) | |||
-- 添加圆点增强现代感与 Tooltip 交互 | |||
for i, v in ipairs(data) do | |||
line_svg = line_svg .. string.format('<circle cx="%f" cy="%f" r="4" fill="#ffffff" stroke="%s" stroke-width="2"><title>%s%s: %s °C</title></circle>', tx(i), ty(v), color, month_labels[i], name, tostring(v)) | |||
end | |||
return line_svg | |||
end | end | ||
svg = svg .. drawLine(d.high, "# | svg = svg .. drawLine(d.high, "#EF4444", "高温") | ||
svg = svg .. drawLine(d.mean, "# | svg = svg .. drawLine(d.mean, "#F59E0B", "均温") | ||
svg = svg .. drawLine(d.low, "# | svg = svg .. drawLine(d.low, "#3B82F6", "低温") | ||
for i, m in ipairs( | -- X 轴月份标签 | ||
svg = svg .. string.format('<text x="%f" y="%d" font-size=" | for i, m in ipairs(month_labels) do | ||
svg = svg .. string.format('<text x="%f" y="%d" font-size="12" fill="#4B5563" text-anchor="middle">%s</text>', tx(i), h - padding.b + 20, m) | |||
end | end | ||
svg = svg .. '</svg>' | svg = svg .. '</svg>' | ||
| 第261行: | 第314行: | ||
local loc_text = stripToNil(args.location) or "气候图表" | local loc_text = stripToNil(args.location) or "气候图表" | ||
-- | -- 现代化设计的 HTML 容器包装 | ||
return string.format('<div class="weather-box-container" style="margin: | return string.format('<div class="weather-box-container" style="margin:1.5em 0; clear:both; font-family:-apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Helvetica, Arial, sans-serif;">\n' .. | ||
'<div style="text-align:right; margin-bottom: | '<div style="text-align:right; margin-bottom:10px;">\n' .. | ||
'<span class="mw-customtoggle-%s" style="font-size: | '<span class="mw-customtoggle-%s" style="font-size:13px; color:#1A73E8; cursor:pointer; user-select:none; background:#F1F3F4; padding:6px 14px; border-radius:16px; font-weight:500; transition: background 0.2s;">切换 图表 / 表格</span>\n' .. | ||
'</div>\n' .. | '</div>\n' .. | ||
'<div class="mw-collapsible" id="mw-customcollapsible-%s" style="margin:0 auto; width: | '<div class="mw-collapsible" id="mw-customcollapsible-%s" style="margin:0 auto; width:100%%; max-width:650px; padding:20px; background:#FFFFFF; border:1px solid #E5E7EB; border-radius:12px; box-shadow:0 4px 6px -1px rgba(0, 0, 0, 0.05);">\n' .. | ||
'<div style="text-align:center; font-weight: | '<div style="text-align:center; font-weight:600; font-size:16px; margin-bottom:20px; color:#1F2937;">%s</div>\n' .. | ||
'%s\n' .. | '%s\n' .. | ||
'<div style="font-size: | '<div style="font-size:13px; text-align:center; margin-top:16px; color:#6B7280;">柯本气候分类:<span style="font-weight:600; color:#2563EB; background:#EFF6FF; padding:4px 10px; border-radius:12px; margin-left:4px;">%s</span></div>\n' .. | ||
'</div>\n' .. | '</div>\n' .. | ||
'<div class="mw-collapsible mw-collapsed" id="mw-customcollapsible-%s" style="overflow-x:auto; width:100%%;">\n' .. | '<div class="mw-collapsible mw-collapsed" id="mw-customcollapsible-%s" style="overflow-x:auto; width:100%%; margin-top:20px;">\n' .. | ||
'%s\n' .. | '%s\n' .. | ||
'</div>\n' .. | '</div>\n' .. | ||
2026年5月12日 (二) 17:20的版本
此模块的文档可以在模块:Weather box/doc创建
local _precision = require('Module:Math')._precision
local function precision(text)
local success, result = pcall(_precision, text)
if success then
return result
end
return 0
end
local function stripToNil(text)
if type(text) == 'string' then
return text:match('(%S.-)%s*$')
end
end
local function isAny(args, suffix)
local months = { 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' }
for _, month in ipairs(months) do
if stripToNil(args[month .. suffix]) then
return true
end
end
end
local function makeLabel(args, options, is_first, base, what)
local first
if isAny(args, ' ' .. what .. ' cm') then
first = 'cm'
else
if isAny(args, ' ' .. what .. ' mm') then
first = 'mm'
else
first = (what:sub(1, 4) == 'snow' or
precision(args['Jan ' .. what .. ' inch'] or '0') < 1)
and 'cm'
or 'mm'
end
end
local second = 'Avs'
if not stripToNil(args['metric first']) then
first, second = second, first
end
if is_first then
if options.wantSingleLine then
first = first .. '(' .. second .. ')'
end
else
first = second
end
return base .. ' ' .. first
end
local function makeSources(frame, args)
local source1 = stripToNil(args.source) or stripToNil(args['source 1'])
local source2 = stripToNil(args['source 2']) or stripToNil(args['source2'])
local result = '|-\n|colspan="14" style="text-align:center;font-size:95%;"|'
local text
if source1 or source2 then
if source1 and source2 then
text = '来源1:' .. source1 .. '\n' .. result .. '来源2:' .. source2
else
text = '来源:' .. (source1 and source1 or source2)
end
else
text = frame:expandTemplate({ title = 'citation needed', args = {date = stripToNil(args.date)} })
end
return result .. text .. '\n|}'
end
local function wantSingle(parm)
parm = (parm or ''):lower()
return not (parm == 'no' or parm == 'n' or parm == '')
end
-- =========================================================================
-- 图表核心计算与现代化渲染
-- =========================================================================
local function calculateKoppen(temps, precips)
local t_mean_annual, p_total, t_hot, t_cold = 0, 0, -99, 99
local s_p, w_p = 0, 0
for i = 1, 12 do
local t, p = tonumber(temps[i]) or 0, tonumber(precips[i]) or 0
t_mean_annual = t_mean_annual + t
p_total = p_total + p
if t > t_hot then t_hot = t end
if t < t_cold then t_cold = t end
if i >= 4 and i <= 9 then s_p = s_p + p else w_p = w_p + p end
end
t_mean_annual = t_mean_annual / 12
local pth = 20 * t_mean_annual + (s_p > p_total * 0.7 and 280 or (w_p > p_total * 0.7 and 0 or 140))
if p_total < pth then
local suffix = t_mean_annual >= 18 and "h" or "k"
return p_total < pth / 2 and "BW" .. suffix or "BS" .. suffix
end
if t_cold >= 18 then return "A" end
if t_hot >= 10 then return t_cold > -3 and "C" or "D" end
return t_hot > 0 and "ET" or "EF"
end
local function makeGraph(frame, args)
local months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
local month_labels = {"1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"}
local d = { high = {}, mean = {}, low = {}, rain = {} }
local max_t, min_t, max_p = -999, 999, 0
for i, m in ipairs(months) do
d.high[i] = tonumber(args[m .. ' high C']) or 0
d.mean[i] = tonumber(args[m .. ' mean C']) or 0
d.low[i] = tonumber(args[m .. ' low C']) or 0
d.rain[i] = tonumber(args[m .. ' precipitation mm']) or tonumber(args[m .. ' rain mm']) or 0
if d.high[i] > max_t then max_t = d.high[i] end
if d.low[i] < min_t then min_t = d.low[i] end
if d.rain[i] > max_p then max_p = d.rain[i] end
end
-- 动态计算刻度范围
max_t = math.ceil((max_t + 5) / 10) * 10
min_t = math.floor((min_t - 5) / 10) * 10
if min_t > 0 then min_t = 0 end
max_p = math.ceil(max_p / 50) * 50
if max_p == 0 then max_p = 100 end
local w, h = 600, 350
local padding = { t = 50, b = 40, l = 50, r = 50 }
local chart_w, chart_h = w - padding.l - padding.r, h - padding.t - padding.b
local function ty(v) return h - padding.b - ((v - min_t) / (max_t - min_t) * chart_h) end
local function py(v) return h - padding.b - (v / max_p * chart_h) end
local function tx(i) return padding.l + (i - 0.5) * (chart_w / 12) end
local svg = string.format('<svg width="100%%" viewBox="0 0 %d %d" style="background:#ffffff; font-family:-apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Helvetica, Arial, sans-serif; display:block;">', w, h)
-- 图例 (Legend)
svg = svg .. '<g font-size="12" fill="#4B5563">'
svg = svg .. '<rect x="' .. (w/2 - 140) .. '" y="15" width="12" height="12" rx="2" fill="#60A5FA" opacity="0.4"/>'
svg = svg .. '<text x="' .. (w/2 - 122) .. '" y="26">降水量</text>'
svg = svg .. '<line x1="' .. (w/2 - 60) .. '" y1="21" x2="' .. (w/2 - 35) .. '" y2="21" stroke="#EF4444" stroke-width="2" stroke-linecap="round"/>'
svg = svg .. '<circle cx="' .. (w/2 - 47.5) .. '" cy="21" r="3" fill="#EF4444"/>'
svg = svg .. '<text x="' .. (w/2 - 27) .. '" y="26">高温</text>'
svg = svg .. '<line x1="' .. (w/2 + 15) .. '" y1="21" x2="' .. (w/2 + 40) .. '" y2="21" stroke="#F59E0B" stroke-width="2" stroke-linecap="round"/>'
svg = svg .. '<circle cx="' .. (w/2 + 27.5) .. '" cy="21" r="3" fill="#F59E0B"/>'
svg = svg .. '<text x="' .. (w/2 + 48) .. '" y="26">均温</text>'
svg = svg .. '<line x1="' .. (w/2 + 90) .. '" y1="21" x2="' .. (w/2 + 115) .. '" y2="21" stroke="#3B82F6" stroke-width="2" stroke-linecap="round"/>'
svg = svg .. '<circle cx="' .. (w/2 + 102.5) .. '" cy="21" r="3" fill="#3B82F6"/>'
svg = svg .. '<text x="' .. (w/2 + 123) .. '" y="26">低温</text>'
svg = svg .. '</g>'
-- 绘制网格与 Y轴刻度 (左侧温度,右侧降水)
local t_step = 10
for v = min_t, max_t, t_step do
local y = ty(v)
if y >= padding.t and y <= h - padding.b then
-- 虚线网格
local stroke_color = (v == 0) and "#9CA3AF" or "#F3F4F6"
local stroke_width = (v == 0) and "1.5" or "1"
local dash = (v == 0) and "" or 'stroke-dasharray="4 4"'
svg = svg .. string.format('<line x1="%d" y1="%f" x2="%d" y2="%f" stroke="%s" stroke-width="%s" %s />', padding.l, y, w - padding.r, y, stroke_color, stroke_width, dash)
-- 左侧温度标签
svg = svg .. string.format('<text x="%d" y="%f" font-size="11" fill="#6B7280" text-anchor="end" alignment-baseline="middle">%d°C</text>', padding.l - 8, y, v)
end
end
local p_step = max_p / 5
for v = 0, max_p, p_step do
local y = py(v)
if y >= padding.t and y <= h - padding.b then
-- 右侧降水标签
svg = svg .. string.format('<text x="%d" y="%f" font-size="11" fill="#9CA3AF" text-anchor="start" alignment-baseline="middle">%d mm</text>', w - padding.r + 8, y, math.floor(v))
end
end
-- 柱状图 (降水)
local bar_w = (chart_w / 12) * 0.5
for i, p_val in ipairs(d.rain) do
local bh = (p_val / max_p * chart_h)
local y = py(p_val)
svg = svg .. string.format('<rect x="%f" y="%f" width="%f" height="%f" fill="#60A5FA" opacity="0.35" rx="2"><title>%s 降水量: %s mm</title></rect>', tx(i) - bar_w/2, y, bar_w, bh, month_labels[i], tostring(p_val))
end
-- 辅助函数:绘制平滑视觉的折线与数据点
local function drawLine(data, color, name)
local pts = ""
for i, v in ipairs(data) do pts = pts .. string.format("%f,%f ", tx(i), ty(v)) end
local line_svg = string.format('<polyline points="%s" fill="none" stroke="%s" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round" />', pts, color)
-- 添加圆点增强现代感与 Tooltip 交互
for i, v in ipairs(data) do
line_svg = line_svg .. string.format('<circle cx="%f" cy="%f" r="4" fill="#ffffff" stroke="%s" stroke-width="2"><title>%s%s: %s °C</title></circle>', tx(i), ty(v), color, month_labels[i], name, tostring(v))
end
return line_svg
end
svg = svg .. drawLine(d.high, "#EF4444", "高温")
svg = svg .. drawLine(d.mean, "#F59E0B", "均温")
svg = svg .. drawLine(d.low, "#3B82F6", "低温")
-- X 轴月份标签
for i, m in ipairs(month_labels) do
svg = svg .. string.format('<text x="%f" y="%d" font-size="12" fill="#4B5563" text-anchor="middle">%s</text>', tx(i), h - padding.b + 20, m)
end
svg = svg .. '</svg>'
local raw_svg = frame:extensionTag('html', svg)
local koppen = calculateKoppen(d.mean, d.rain)
return raw_svg, koppen
end
-- =========================================================================
local function getDefinitions(frame, args, options)
local function _if(parm, a, b) return stripToNil(args[parm]) and a or b or '' end
local function _ifset(parm, a) return stripToNil(args[parm]) and args[parm] or a end
local function _ifany(suffix) return isAny(args, suffix) end
local function _ifSingle(a, b) return options.wantSingleLine and a or b or '' end
local location = _if('location', args.location, '{{{location}}}')
local navbarText
if not stripToNil(args.open) and stripToNil(args.name) then
local navbar = require('Module:Navbar')._navbar
navbarText = navbar({' ' .. location, args.name, collapsible=1})
end
return {
'{| class="wikitable ' .. _if('open', '', 'mw-collapsible' .. _if('collapsed', ' mw-collapsed')) .. '" style="width:' .. _ifset('width', '100%') .. '; text-align:center; line-height: 1.2em; margin: 0 auto;"' ..
_if('open', '\n|+ ' .. location, '\n|-\n!colspan="14" | ' .. _if('name', navbarText, ' ' .. location)) ..
[=[
|-
!scope="row" |月份
!scope="col" |1月
!scope="col" |2月
!scope="col" |3月
!scope="col" |4月
!scope="col" |5月
!scope="col" |6月
!scope="col" |7月
!scope="col" |8月
!scope="col" |9月
!scope="col" |10月
!scope="col" |11月
!scope="col" |12月
!scope="col" style="border-left-width:medium" |全年
]=],
{WANTROW = _ifany(' maximum humidex') and (_ifset('metric first') or options.wantSingleLine), mode = 'basic', group_name = 'maximum humidex', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '历史最高[[湿热指数]]', annual_mode = 'max'},
{WANTROW = _ifany(' record high C') or _ifany(' record high F'), mode = 'temperature', group_name = 'record high', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '历史最高温 °' .. _if('metric first', 'C', 'F') .. _ifSingle('(°' .. _if('metric first', 'F', 'C') .. ')'), annual_mode = 'max'},
{WANTROW = _ifany(' avg record high C') or _ifany(' avg record high F'), mode = 'temperature', group_name = 'avg record high', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '平均最高温 °' .. _if('metric first', 'C', 'F') .. _ifSingle('(°' .. _if('metric first', 'F', 'C') .. ')'), annual_mode = 'max'},
{WANTROW = _ifany(' high C') or _ifany(' high F'), mode = 'temperature', group_name = 'high', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '平均高温 °' .. _if('metric first', 'C', 'F') .. _ifSingle('(°' .. _if('metric first', 'F', 'C') .. ')'), annual_mode = 'avg'},
{WANTROW = _ifany(' mean C') or _ifany(' mean F'), mode = 'temperature', group_name = 'mean', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '日均气温 °' .. _if('metric first', 'C', 'F') .. _ifSingle('(°' .. _if('metric first', 'F', 'C') .. ')'), annual_mode = 'avg'},
{WANTROW = _ifany(' low C') or _ifany(' low F'), mode = 'temperature', group_name = 'low', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '平均低温 °' .. _if('metric first', 'C', 'F') .. _ifSingle('(°' .. _if('metric first', 'F', 'C') .. ')'), annual_mode = 'avg'},
{WANTROW = _ifany(' avg record low C') or _ifany(' avg record low F'), mode = 'temperature', group_name = 'avg record low', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '平均最低温 °' .. _if('metric first', 'C', 'F') .. _ifSingle('(°' .. _if('metric first', 'F', 'C') .. ')'), annual_mode = 'min'},
{WANTROW = _ifany(' record low C') or _ifany(' record low F'), mode = 'temperature', group_name = 'record low', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '历史最低温 °' .. _if('metric first', 'C', 'F') .. _ifSingle('(°' .. _if('metric first', 'F', 'C') .. ')'), annual_mode = 'min'},
{WANTROW = _ifany(' chill') and (_ifset('metric first') or options.wantSingleLine), mode = 'basic', group_name = 'chill', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '历史最低[[風寒指數]]', annual_mode = 'min'},
{WANTROW = _ifany(' precipitation cm') or _ifany(' precipitation mm') or _ifany(' precipitation inch'), mode = 'precipitation', group_name = 'precipitation', color_scheme = _ifset('precipitation colour', 'p'), date_mode = true, scale_factor = '1', prefer_cm = precision(_ifset('Jan precipitation inch', '0')) < 1, label = makeLabel(args, options, true, '平均[[降水量]]', 'precipitation'), annual_mode = 'sum'},
{WANTROW = _ifany(' rain cm') or _ifany(' rain mm') or _ifany(' rain inch'), mode = 'precipitation', group_name = 'rain', color_scheme = _ifset('rain colour', 'p'), date_mode = true, scale_factor = '1', prefer_cm = precision(_ifset('Jan rain inch', '0')) < 1, label = makeLabel(args, options, true, '平均降雨量', 'rain'), annual_mode = 'sum'},
{WANTROW = _ifany(' snow cm') or _ifany(' snow mm') or _ifany(' snow inch'), mode = 'precipitation', group_name = 'snow', prefer_cm = true, color_scheme = _ifset('snow colour', 'p'), date_mode = true, scale_factor = '1', label = makeLabel(args, options, true, '平均降雪量', 'snow'), annual_mode = 'sum'},
{WANTROW = _ifany(' snow depth cm') or _ifany(' snow depth mm') or _ifany(' snow depth inch'), mode = 'precipitation', group_name = 'snow depth', prefer_cm = true, color_scheme = _ifset('snow colour', 'p'), scale_factor = '0.2', label = makeLabel(args, options, true, '平均最大雪深', '雪深'), annual_mode = 'max'},
{WANTROW = not options.wantSingleLine and _ifany(' maximum humidex'), mode = 'basic', group_name = 'maximum humidex', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '[[湿热指数]]', annual_mode = 'max', second_line = true},
{WANTROW = not options.wantSingleLine and (_ifany(' record high C') or _ifany(' record high F')), mode = 'temperature', group_name = 'record high', second_line = true, color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '历史最高温 °' .. _if('metric first', 'F', 'C'), annual_mode = 'max'},
{WANTROW = not options.wantSingleLine and (_ifany(' high C') or _ifany(' high F')), mode = 'temperature', group_name = 'high', second_line = true, color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '平均高温 °' .. _if('metric first', 'F', 'C'), annual_mode = 'avg'},
{WANTROW = not options.wantSingleLine and (_ifany(' mean C') or _ifany(' mean F')), mode = 'temperature', group_name = 'mean', second_line = true, color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '日均气温 °' .. _if('metric first', 'F', 'C'), show = _if('metric first', '2', '1'), annual_mode = 'avg'},
{WANTROW = not options.wantSingleLine and (_ifany(' low C') or _ifany(' low F')), mode = 'temperature', group_name = 'low', second_line = true, color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '平均低温 °' .. _if('metric first', 'F', 'C'), show = _if('metric first', '2', '1'), annual_mode = 'avg'},
{WANTROW = not options.wantSingleLine and (_ifany(' record low C') or _ifany(' record low F')), mode = 'temperature', group_name = 'record low', second_line = true, color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '历史最低温 °' .. _if('metric first', 'F', 'C'), show = _if('metric first', '2', '1'), annual_mode = 'min'},
{WANTROW = not options.wantSingleLine and (_ifany(' chill') and _if('metric first')), mode = 'basic', group_name = 'chill', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '[[風寒指數]]', annual_mode = 'min'},
{WANTROW = not options.wantSingleLine and (_ifany(' precipitation cm') or _ifany(' precipitation mm') or _ifany(' precipitation inch')), mode = 'precipitation', group_name = 'precipitation', second_line = true, color_scheme = _ifset('precipitation colour', 'p'), date_mode = true, scale_factor = '1', prefer_cm = precision(_ifset('Jan precipitation inch', '0')) < 1, label = makeLabel(args, options, false, '平均[[降水量]]', 'precipitation'), annual_mode = 'sum'},
{WANTROW = not options.wantSingleLine and (_ifany(' rain cm') or _ifany(' rain mm') or _ifany(' rain inch')), mode = 'precipitation', group_name = 'rain', second_line = true, color_scheme = _ifset('rain colour', 'p'), date_mode = true, scale_factor = '1', prefer_cm = precision(_ifset('Jan rain inch', '0')) < 1, label = makeLabel(args, options, false, '平均降雨量', 'rain'), annual_mode = 'sum'},
{WANTROW = not options.wantSingleLine and (_ifany(' snow cm') or _ifany(' snow mm') or _ifany(' snow inch')), mode = 'precipitation', group_name = 'snow', second_line = true, prefer_cm = true, color_scheme = _ifset('snow colour', 'p'), date_mode = true, scale_factor = '1', label = makeLabel(args, options, false, '平均降雪量', 'snow'), annual_mode = 'sum'},
{WANTROW = not options.wantSingleLine and (_ifany(' snow depth cm') or _ifany(' snow depth mm') or _ifany(' snow depth inch')), mode = 'precipitation', group_name = 'snow depth', second_line = true, prefer_cm = true, color_scheme = _ifset('snow colour', 'p'), scale_factor = '0.2', label = makeLabel(args, options, false, '平均最大雪深', '雪深'), annual_mode = 'max'},
{WANTROW = _ifany(' precipitation days'), mode = 'basic', group_name = 'precipitation days', color_scheme = _ifset('precip days colour', 'd'), date_mode = true, scale_factor = '1', label = '平均降水天数' .. _if('unit precipitation days', '<span style="font-size:90%;" class="nowrap">(≥ ' .. _ifset('unit precipitation days', '') .. ')</span>'), annual_mode = 'sum'},
{WANTROW = _ifany(' rain days'), mode = 'basic', group_name = 'rain days', color_scheme = _ifset('precip days colour', 'd'), date_mode = true, scale_factor = '1', label = '平均降雨天数' .. _if('unit rain days', '<span style="font-size:90%;" class="nowrap">(≥ ' .. _ifset('unit rain days', '') .. ')</span>'), annual_mode = 'sum'},
{WANTROW = _ifany(' snow days'), mode = 'basic', group_name = 'snow days', color_scheme = _ifset('precip days colour', 'd'), date_mode = true, scale_factor = '1', label = '平均降雪天数' .. _if('unit snow days', '<span style="font-size:90%;" class="nowrap">(≥ ' .. _ifset('unit snow days', '') .. ')</span>'), annual_mode = 'sum'},
{WANTROW = _ifany(' humidity'), mode = 'basic', group_name = 'humidity', color_scheme = _ifset('humidity colour', 'h'), scale_factor = '1', label = '平均[[相對濕度]](%)' .. _if('time day', ' <span style="font-size:90%;" class="nowrap">(' .. _ifset('time day', '') .. ')</span>') .. _if('daily', ' <span style="font-size:90%;" class="nowrap">(日均)</span>'), annual_mode = 'avg'},
{WANTROW = _ifany(' afthumidity'), mode = 'basic', group_name = 'afthumidity', color_scheme = _ifset('humidity colour', 'h'), scale_factor = '1', label = '平均午後[[相對濕度]](%)' .. _if('time day', ' <span style="font-size:90%;" class="nowrap">(' .. _ifset('time day', '') .. ')</span>') .. _if('daily', ' <span style="font-size:90%;" class="nowrap">(日均)</span>'), annual_mode = 'avg'},
{WANTROW = _ifany(' dew point C') or _ifany(' dew point F'), mode = 'temperature', group_name = 'dew point', color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '平均[[露点]] °' .. _if('metric first', 'C', 'F') .. _ifSingle('(°' .. _if('metric first', 'F', 'C') .. ')'), annual_mode = 'avg'},
{WANTROW = not options.wantSingleLine and (_ifany(' dew point C') or _ifany(' dew point F')), mode = 'temperature', group_name = 'dew point', second_line = true, color_scheme = _ifset('temperature colour', 't'), scale_factor = '1', label = '平均[[露点]] °' .. _if('metric first', 'F', 'C'), show = _if('metric first', '2', '1'), annual_mode = 'avg'},
{WANTROW = _ifany(' sun'), mode = 'basic', group_name = 'sun', color_scheme = _ifset('sun colour', 's'), date_mode = true, scale_factor = '1', label = '月均[[日照時數]]', annual_mode = 'sum'},
{WANTROW = _ifany('d sun'), mode = 'basic', group_name = 'd sun', color_scheme = _ifset('sun colour', 's'), include_space = false, scale_factor = '30.44', label = '日均[[日照時數]]', annual_mode = 'avg'},
{WANTROW = _ifany(' light'), mode = 'basic', group_name = ' light', color_scheme = _ifset('sun colour', 's'), include_space = false, scale_factor = '30.44', label = '日均[[白天|昼长]]', annual_mode = 'avg'},
{WANTROW = _ifany(' percentsun'), mode = 'basic', group_name = 'percentsun', color_scheme = _ifset('sun colour', 's'), scale_factor = '7.2', label = '[[日照時數|可照]]百分比', annual_mode = 'avg'},
{WANTROW = _ifany(' uv'), mode = 'basic', group_name = 'uv', color_scheme = _ifset('uv colour', 'u'), scale_factor = '1', label = '平均[[紫外线指数]]', annual_mode = 'avg'},
makeSources(frame, args),
}
end
local function main(frame)
local sandbox = frame:getTitle():find('sandbox', 1, true) and '/sandbox' or ''
local buildRow = require('Module:Weather box/row' .. sandbox)._buildRow
local args = frame:getParent().args
local options = {
wantSingleLine = wantSingle(args['single line']),
sandbox = sandbox,
}
local results = {}
for i, definition in ipairs(getDefinitions(frame, args, options)) do
local row
if type(definition) == 'string' then
row = definition
elseif definition.WANTROW then
row = buildRow(definition, args, options)
else
row = ''
end
results[i] = row
end
local tableText = table.concat(results)
if stripToNil(args['hide graph']) == 'Y' or stripToNil(args['hide graph']) == 'y' then
return '<div class="weather-box-container" style="clear:both;">\n' .. tableText .. '\n</div>'
else
local uid = "weatherbox_" .. tostring(math.random(100000, 999999))
local raw_svg, koppen = makeGraph(frame, args)
local loc_text = stripToNil(args.location) or "气候图表"
-- 现代化设计的 HTML 容器包装
return string.format('<div class="weather-box-container" style="margin:1.5em 0; clear:both; font-family:-apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Helvetica, Arial, sans-serif;">\n' ..
'<div style="text-align:right; margin-bottom:10px;">\n' ..
'<span class="mw-customtoggle-%s" style="font-size:13px; color:#1A73E8; cursor:pointer; user-select:none; background:#F1F3F4; padding:6px 14px; border-radius:16px; font-weight:500; transition: background 0.2s;">切换 图表 / 表格</span>\n' ..
'</div>\n' ..
'<div class="mw-collapsible" id="mw-customcollapsible-%s" style="margin:0 auto; width:100%%; max-width:650px; padding:20px; background:#FFFFFF; border:1px solid #E5E7EB; border-radius:12px; box-shadow:0 4px 6px -1px rgba(0, 0, 0, 0.05);">\n' ..
'<div style="text-align:center; font-weight:600; font-size:16px; margin-bottom:20px; color:#1F2937;">%s</div>\n' ..
'%s\n' ..
'<div style="font-size:13px; text-align:center; margin-top:16px; color:#6B7280;">柯本气候分类:<span style="font-weight:600; color:#2563EB; background:#EFF6FF; padding:4px 10px; border-radius:12px; margin-left:4px;">%s</span></div>\n' ..
'</div>\n' ..
'<div class="mw-collapsible mw-collapsed" id="mw-customcollapsible-%s" style="overflow-x:auto; width:100%%; margin-top:20px;">\n' ..
'%s\n' ..
'</div>\n' ..
'</div>', uid, uid, loc_text, raw_svg, koppen, uid, tableText)
end
end
return {
main = main,
}