Module:BubbleGraph: Difference between revisions
From IdleOn MMO Wiki
mNo edit summary |
mNo edit summary |
||
(37 intermediate revisions by the same user not shown) | |||
Line 4: | Line 4: | ||
local mult = 10 ^ (numDecimalPlaces or 0) | local mult = 10 ^ (numDecimalPlaces or 0) | ||
return math.floor(num * mult + 0.5) / mult | return math.floor(num * mult + 0.5) / mult | ||
end | |||
function round_format(num) | |||
local str = tostring(num) | |||
return str:find("%.") and str:gsub("0+$", ""):gsub("%.$", "") or str | |||
end | end | ||
Line 43: | Line 48: | ||
local max_levels = 1000 | local max_levels = 1000 | ||
local step = 20 | local step = 20 | ||
local graph_width = | local graph_width = 1330.8 | ||
local graph_height = 250 | local graph_height = 250 | ||
local points = {} | local points = {} | ||
local threshold_level = x2 * 90 / (100 - 90) | |||
local max_bonus = 0 | local max_bonus = 0 | ||
for level = 1, max_levels do | for level = 1, max_levels do | ||
if level == 1 or level % step == 0 then | if level == threshold_level then | ||
local bonus = BubbleGraph.calculate_bonus(func, level, x1, x2) | |||
table.insert(points, {level = level, bonus = bonus}) | |||
elseif level == 1 or level % step == 0 then | |||
local bonus = BubbleGraph.calculate_bonus(func, level, x1, x2) | local bonus = BubbleGraph.calculate_bonus(func, level, x1, x2) | ||
table.insert(points, {level = level, bonus = bonus}) | table.insert(points, {level = level, bonus = bonus}) | ||
Line 57: | Line 67: | ||
end | end | ||
local column_color_start, column_color_end, background_color_start, background_color_end, bubble_image_name | local column_color_start, column_color_end, background_color_start, background_color_end, bubble_image_name, displayVal | ||
if bubble_color == "orange" then | if bubble_color == "orange" then | ||
Line 88: | Line 98: | ||
mw.html.create("div"):css( | mw.html.create("div"):css( | ||
{ | { | ||
width = graph_width | width = graph_width .. "px", | ||
height = graph_height + 100 .. "px", | height = graph_height + 100 .. "px", | ||
position = "relative", | position = "relative", | ||
Line 96: | Line 106: | ||
} | } | ||
) | ) | ||
if bubble_name and bubble_number == '' then | |||
displayVal = "none" | |||
else | |||
displayVal = "initial" | |||
end | |||
local bubble_header = | local bubble_header = | ||
mw.html.create("div"):css( | mw.html.create("div"):css( | ||
Line 103: | Line 119: | ||
top = "-10px", | top = "-10px", | ||
left = "50%", | left = "50%", | ||
width = " | width = graph_width + 8 .. "px", | ||
["font-size"] = "35px", | ["font-size"] = "35px", | ||
["transform"] = "translateX(-50%)" | ["transform"] = "translateX(-50%)", | ||
["display"] = displayVal | |||
} | } | ||
):wikitext(string.format("[[File:%s.png|link=]]%s", bubble_image_name, bubble_name)) | ):wikitext(string.format("[[File:%s.png|link=]]%s", bubble_image_name, bubble_name)) | ||
Line 116: | Line 133: | ||
position = "absolute", | position = "absolute", | ||
top = "20%", | top = "20%", | ||
left = " | left = "-2%", | ||
height = graph_height .. "px", | height = graph_height .. "px", | ||
["writing-mode"] = "sideways-lr" | ["writing-mode"] = "sideways-lr" | ||
Line 132: | Line 148: | ||
["align-items"] = "flex-end", | ["align-items"] = "flex-end", | ||
position = "absolute", | position = "absolute", | ||
top = "60px", | top = "60px", | ||
["background-image"] = string.format( | ["background-image"] = string.format( | ||
Line 144: | Line 159: | ||
} | } | ||
) | ) | ||
for _, point in ipairs(points) do | for _, point in ipairs(points) do | ||
Line 151: | Line 164: | ||
if func == "decay" or func == "decayMulti" then | if func == "decay" or func == "decayMulti" then | ||
if point. | if point.level >= threshold_level then | ||
local reduction_factor = math.exp(-((point. | local reduction_factor = math.exp(-((point.level - threshold_level) / 100)) | ||
height = height * reduction_factor | height = height * reduction_factor | ||
end | end | ||
end | end | ||
local gradient_ratio = (point.level - 1) / ( | local gradient_ratio | ||
local color | |||
if point.level <= threshold_level then | |||
gradient_ratio = (point.level - 1) / (threshold_level - 1) | |||
color = | |||
string.format( | |||
"#%02x%02x%02x", | |||
math.floor( | |||
tonumber(column_color_start:sub(2, 3), 16) + | |||
gradient_ratio * | |||
(tonumber(column_color_end:sub(2, 3), 16) - tonumber(column_color_start:sub(2, 3), 16)) | |||
), | |||
math.floor( | |||
tonumber(column_color_start:sub(4, 5), 16) + | |||
gradient_ratio * | |||
gradient_ratio * | (tonumber(column_color_end:sub(4, 5), 16) - tonumber(column_color_start:sub(4, 5), 16)) | ||
(tonumber(column_color_end:sub(6, 7), 16) - tonumber( | ), | ||
math.floor( | |||
tonumber(column_color_start:sub(6, 7), 16) + | |||
gradient_ratio * | |||
(tonumber(column_color_end:sub(6, 7), 16) - tonumber(column_color_start:sub(6, 7), 16)) | |||
) | |||
) | |||
else | |||
gradient_ratio = (point.level - threshold_level) / (max_levels - threshold_level) | |||
color = | |||
string.format( | |||
"#%02x%02x%02x", | |||
math.floor( | |||
tonumber(column_color_end:sub(2, 3), 16) + | |||
gradient_ratio * | |||
(tonumber(column_color_start:sub(2, 3), 16) - tonumber(column_color_end:sub(2, 3), 16)) | |||
), | |||
math.floor( | |||
tonumber(column_color_end:sub(4, 5), 16) + | |||
gradient_ratio * | |||
(tonumber(column_color_start:sub(4, 5), 16) - tonumber(column_color_end:sub(4, 5), 16)) | |||
), | |||
math.floor( | |||
tonumber(column_color_end:sub(6, 7), 16) + | |||
gradient_ratio * | |||
(tonumber(column_color_start:sub(6, 7), 16) - tonumber(column_color_end:sub(6, 7), 16)) | |||
) | |||
) | ) | ||
end | |||
local column = | local column = | ||
Line 186: | Line 225: | ||
position = "relative" | position = "relative" | ||
} | } | ||
) | ):attr("title", string.format("Level: %d\nBonus: %s", point.level, round_format(round(point.bonus, 3)))) | ||
:addClass("chart-column") | |||
local bonus_value = | local bonus_value = round(point.bonus, 3) | ||
local height_DN = | local height_DN = 60 | ||
local padding_top = 5 | local padding_top = 5 | ||
local padding_bottom = 5 | local padding_bottom = 5 | ||
Line 211: | Line 251: | ||
["transform"] = "translateX(-50%)" | ["transform"] = "translateX(-50%)" | ||
} | } | ||
):wikitext(bonus_value) | ):wikitext(round_format(bonus_value)) | ||
column:tag("span"):css( | column:tag("span"):css( | ||
Line 231: | Line 271: | ||
position = "absolute", | position = "absolute", | ||
top = "95%", | top = "95%", | ||
width = graph_width + 8 .. "px" | |||
width = graph_width .. "px" | |||
} | } | ||
):wikitext("Level") | ):wikitext("Level") | ||
container:node(x_axis) | container:node(x_axis) | ||
return tostring(container) | return tostring(container) | ||
end | end | ||
Line 246: | Line 285: | ||
local func = args.func | local func = args.func | ||
local bubble_color = args.bubble_color or args.color | local bubble_color = args.bubble_color or args.color | ||
local bubble_name = args.bubble_name or args.name | local bubble_name = args.bubble_name or args.name or '' | ||
local bubble_number = args.bubble_number or args.number | local bubble_number = args.bubble_number or args.number or '' | ||
local max_levels = tonumber(args.max_levels) or 1000 | |||
local step = tonumber(args.step) or 20 | |||
return BubbleGraph.generate_graph(x1, x2, func, bubble_color, bubble_name, bubble_number) | return BubbleGraph.generate_graph(x1, x2, func, bubble_color, bubble_name, bubble_number) |
Latest revision as of 05:24, 12 December 2024
Documentation for this module may be created at Module:BubbleGraph/doc
local BubbleGraph = {}
function round(num, numDecimalPlaces)
local mult = 10 ^ (numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
function round_format(num)
local str = tostring(num)
return str:find("%.") and str:gsub("0+$", ""):gsub("%.$", "") or str
end
function BubbleGraph.calculate_bonus(func, level, x1, x2)
local result = 0
if func == "add" then
if x2 ~= 0 then
result = (((x1 + x2) / x2 + 0.5 * (level - 1)) / (x1 / x2)) * level * x1
else
result = level * x1
end
elseif func == "decay" then
result = (level * x1) / (level + x2)
elseif func == "intervalAdd" then
result = x1 + math.floor(level / x2)
elseif func == "decayMulti" then
result = 1 + (level * x1) / (level + x2)
elseif func == "bigBase" then
result = x1 + x2 * level
elseif func == "addLower" then
result = x1 + x2 * (level + 1)
elseif func == "decayLower" or func == "decayMultiLower" then
result = x1 * (level + 1) / (level + 1 + x2) - x1 * level / (level + x2)
elseif func == "bigBaseLower" then
result = x2
elseif func == "intervalAddLower" then
result = math.max(math.floor((level + 1) / x2), 0) - math.max(math.floor(level / x2), 0)
elseif func == "reduce" then
result = x1 - x2 * level
elseif func == "reduceLower" then
result = x1 - x2 * (level + 1)
else
result = 0
end
return round(result, 3)
end
function BubbleGraph.generate_graph(x1, x2, func, bubble_color, bubble_name, bubble_number)
local max_levels = 1000
local step = 20
local graph_width = 1330.8
local graph_height = 250
local points = {}
local threshold_level = x2 * 90 / (100 - 90)
local max_bonus = 0
for level = 1, max_levels do
if level == threshold_level then
local bonus = BubbleGraph.calculate_bonus(func, level, x1, x2)
table.insert(points, {level = level, bonus = bonus})
elseif level == 1 or level % step == 0 then
local bonus = BubbleGraph.calculate_bonus(func, level, x1, x2)
table.insert(points, {level = level, bonus = bonus})
if bonus > max_bonus then
max_bonus = bonus
end
end
end
local column_color_start, column_color_end, background_color_start, background_color_end, bubble_image_name, displayVal
if bubble_color == "orange" then
column_color_start = "#ffe787"
column_color_end = "#690e0e"
background_color_start = "#ffffff"
background_color_end = "#ef7500"
bubble_image_name = "OrangeBubble" .. bubble_number
elseif bubble_color == "green" then
column_color_start = "#bfffab"
column_color_end = "#09591a"
background_color_start = "#f7f7ff"
background_color_end = "#3fe855"
bubble_image_name = "GreenBubble" .. bubble_number
elseif bubble_color == "purple" then
column_color_start = "#fcc1ff"
column_color_end = "#350b6a"
background_color_start = "#fffdfa"
background_color_end = "#ca51ee"
bubble_image_name = "PurpleBubble" .. bubble_number
elseif bubble_color == "yellow" then
column_color_start = "#f7ffbd"
column_color_end = "#714200"
background_color_start = "#f7fffa"
background_color_end = "#ecc200"
bubble_image_name = "YellowBubble" .. bubble_number
end
local container =
mw.html.create("div"):css(
{
width = graph_width .. "px",
height = graph_height + 100 .. "px",
position = "relative",
["font-family"] = "'Idleon'",
["text-align"] = "center",
["margin-bottom"] = "50px"
}
)
if bubble_name and bubble_number == '' then
displayVal = "none"
else
displayVal = "initial"
end
local bubble_header =
mw.html.create("div"):css(
{
position = "absolute",
top = "-10px",
left = "50%",
width = graph_width + 8 .. "px",
["font-size"] = "35px",
["transform"] = "translateX(-50%)",
["display"] = displayVal
}
):wikitext(string.format("[[File:%s.png|link=]]%s", bubble_image_name, bubble_name))
container:node(bubble_header)
local y_axis =
mw.html.create("div"):css(
{
position = "absolute",
top = "20%",
left = "-2%",
height = graph_height .. "px",
["writing-mode"] = "sideways-lr"
}
):wikitext("Bonus")
container:node(y_axis)
local root =
mw.html.create("div"):css(
{
width = graph_width .. "px",
height = graph_height .. "px",
display = "flex",
["align-items"] = "flex-end",
position = "absolute",
top = "60px",
["background-image"] = string.format(
"linear-gradient(%s, %s)",
background_color_start,
background_color_end
),
border = "1px solid #000",
["border-radius"] = "3px",
padding = "3px"
}
)
for _, point in ipairs(points) do
local height = math.floor((point.bonus / max_bonus) * graph_height)
if func == "decay" or func == "decayMulti" then
if point.level >= threshold_level then
local reduction_factor = math.exp(-((point.level - threshold_level) / 100))
height = height * reduction_factor
end
end
local gradient_ratio
local color
if point.level <= threshold_level then
gradient_ratio = (point.level - 1) / (threshold_level - 1)
color =
string.format(
"#%02x%02x%02x",
math.floor(
tonumber(column_color_start:sub(2, 3), 16) +
gradient_ratio *
(tonumber(column_color_end:sub(2, 3), 16) - tonumber(column_color_start:sub(2, 3), 16))
),
math.floor(
tonumber(column_color_start:sub(4, 5), 16) +
gradient_ratio *
(tonumber(column_color_end:sub(4, 5), 16) - tonumber(column_color_start:sub(4, 5), 16))
),
math.floor(
tonumber(column_color_start:sub(6, 7), 16) +
gradient_ratio *
(tonumber(column_color_end:sub(6, 7), 16) - tonumber(column_color_start:sub(6, 7), 16))
)
)
else
gradient_ratio = (point.level - threshold_level) / (max_levels - threshold_level)
color =
string.format(
"#%02x%02x%02x",
math.floor(
tonumber(column_color_end:sub(2, 3), 16) +
gradient_ratio *
(tonumber(column_color_start:sub(2, 3), 16) - tonumber(column_color_end:sub(2, 3), 16))
),
math.floor(
tonumber(column_color_end:sub(4, 5), 16) +
gradient_ratio *
(tonumber(column_color_start:sub(4, 5), 16) - tonumber(column_color_end:sub(4, 5), 16))
),
math.floor(
tonumber(column_color_end:sub(6, 7), 16) +
gradient_ratio *
(tonumber(column_color_start:sub(6, 7), 16) - tonumber(column_color_end:sub(6, 7), 16))
)
)
end
local column =
mw.html.create("div"):css(
{
flex = "1",
height = height .. "px",
["background-color"] = color,
position = "relative"
}
):attr("title", string.format("Level: %d\nBonus: %s", point.level, round_format(round(point.bonus, 3))))
:addClass("chart-column")
local bonus_value = round(point.bonus, 3)
local height_DN = 60
local padding_top = 5
local padding_bottom = 5
local top_value, bottom_value
if height >= height_DN + padding_top then
top_value = padding_top
else
bottom_value = padding_bottom
end
column:tag("span"):css(
{
position = "absolute",
top = top_value and string.format("%dpx", top_value) or nil,
bottom = bottom_value and string.format("%dpx", bottom_value) or nil,
["writing-mode"] = "sideways-lr",
color = "#fff",
["text-shadow"] = "-.065em 0 #000, 0 .065em #000, .065em 0 #000, 0 -.065em #000",
left = "50%",
["transform"] = "translateX(-50%)"
}
):wikitext(round_format(bonus_value))
column:tag("span"):css(
{
position = "relative",
bottom = "-100%",
["font-size"] = "10px"
}
):wikitext(point.level)
root:node(column)
end
container:node(root)
local x_axis =
mw.html.create("div"):css(
{
position = "absolute",
top = "95%",
width = graph_width + 8 .. "px"
}
):wikitext("Level")
container:node(x_axis)
return tostring(container)
end
function BubbleGraph.render(frame)
local args = frame.args or frame:getParent().args
local x1 = tonumber(args.x1)
local x2 = tonumber(args.x2)
local func = args.func
local bubble_color = args.bubble_color or args.color
local bubble_name = args.bubble_name or args.name or ''
local bubble_number = args.bubble_number or args.number or ''
local max_levels = tonumber(args.max_levels) or 1000
local step = tonumber(args.step) or 20
return BubbleGraph.generate_graph(x1, x2, func, bubble_color, bubble_name, bubble_number)
end
return BubbleGraph