| 🌟 | 現在、 鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。 |
「モジュール:Utility/TableUtil」の版間の差分
ナビゲーションに移動
検索に移動
(LineCellにgridの実装を追加(自動で幅を調整できる改善含む)) |
(フッターの軸表示機能を実装) |
||
| 38行目: | 38行目: | ||
if type(opts.cellClass) == 'string' then | if type(opts.cellClass) == 'string' then | ||
obj.cellClass = opts.cellClass | obj.cellClass = opts.cellClass | ||
end | |||
if type(opts.footerClass) == 'string' then | |||
obj.footerClass = opts.footerClass | |||
end | end | ||
| 83行目: | 87行目: | ||
end | end | ||
return headerCell | return headerCell | ||
end | |||
-- [Function] Render footer | |||
function __TableUtil__Cell:renderFooter(footerRow) | |||
if self.headerColspan <= 0 then | |||
return nil | |||
end | |||
local footerCell = footerRow:tag('td') | |||
if self.footerClass then | |||
footerCell:addClass(self.footerClass) | |||
end | |||
if self.headerColspan > 1 then | |||
footerCell:attr('colspan', self.headerColspan) | |||
end | |||
return footerCell | |||
end | end | ||
| 195行目: | 215行目: | ||
function __TableUtil__LineCell.__new(typename, name, dataIndex, opts) | function __TableUtil__LineCell.__new(typename, name, dataIndex, opts) | ||
local obj = __TableUtil__Cell.__new(typename, name, opts) | local obj = __TableUtil__Cell.__new(typename, name, opts) | ||
obj.__cell__render = obj.render | obj.__cell__render = obj.render | ||
obj.__cell__renderFooter = obj.renderFooter | |||
obj.dataIndex = dataIndex | obj.dataIndex = dataIndex | ||
if type(opts) == 'table' then | if type(opts) == 'table' then | ||
| 240行目: | 261行目: | ||
self._ticks = scale:ticks(self.preferredGridCount) | self._ticks = scale:ticks(self.preferredGridCount) | ||
end | end | ||
end | |||
-- [Function] Render footer | |||
function __TableUtil__LineCell:renderFooter(footerRow) | |||
local footerCell = self:__cell__renderFooter(footerRow) | |||
if self.gridEnabled and footerCell then | |||
footerCell | |||
:addClass('st-axis') | |||
:addClass(string.format('st-axis-%d', #self._ticks + 2)) | |||
local list = footerCell:tag('ul') | |||
list:tag('li'):wikitext(self._scale.domain[1]) | |||
for _, tick in ipairs(self._ticks) do | |||
list:tag('li'):wikitext(tick) | |||
end | |||
end | |||
return footerCell | |||
end | end | ||
| 320行目: | 358行目: | ||
function valueKlass.new(name, dataIndex, opts) | function valueKlass.new(name, dataIndex, opts) | ||
local obj = superklass.__new(valuetype, name, dataIndex, opts) | local obj = superklass.__new(valuetype, name, dataIndex, opts) | ||
obj.__super__render = obj.render | obj.__super__render = obj.render | ||
obj.__super__renderHeader = obj.renderHeader | |||
obj.__super__renderFooter = obj.renderFooter | |||
obj.mixinValue = true | obj.mixinValue = true | ||
if type(opts) == 'table' then | if type(opts) == 'table' then | ||
| 442行目: | 482行目: | ||
m:render(row, d, i, datainfo) | m:render(row, d, i, datainfo) | ||
end | end | ||
end | |||
-- Build footer | |||
local footerRow = tbl:tag('tr'):addClass('sortbottom') | |||
for _, m in ipairs(metadata) do | |||
-- Render footer | |||
m:renderFooter(footerRow) | |||
end | end | ||
2021年8月21日 (土) 12:30時点における版
このモジュールについての説明文ページを モジュール:Utility/TableUtil/doc に作成できます
-- Table Utility for MediaWiki
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Copyright (C) 2021 mntone. All rights reserved.
-- This script is released under the MIT License.
-- ====================
-- namespace: TableUtil
-- ====================
local tableutil = {}
-- =====
-- Config
-- =====
local aw = require('Module:Utility/Library')
local scale = require('Module:Utility/Scale')
local function __passthrough(num)
return num
end
-- ==========
-- type: Cell
-- ==========
local __TableUtil__CellType__Cell = 'cell'
local __TableUtil__Cell = {
__typename = __TableUtil__CellType__Cell,
}
-- [Constructor]
function __TableUtil__Cell.__new(typename, name, opts)
local obj = {
typename = typename,
name = name,
}
if opts then
if type(opts.attributes) == 'table' then
obj.attributes = opts.attributes
end
if type(opts.cellClass) == 'string' then
obj.cellClass = opts.cellClass
end
if type(opts.footerClass) == 'string' then
obj.footerClass = opts.footerClass
end
if type(opts.headerClass) == 'string' then
obj.headerClass = opts.headerClass
end
if type(opts.headerColspan) == 'number' then
obj.headerColspan = opts.headerColspan
else
obj.headerColspan = 1
end
if type(opts.headerStyle) == 'table' then
obj.headerStyle = opts.headerStyle
end
else
obj.headerColspan = 1
end
return setmetatable(obj, { __index = __TableUtil__Cell })
end
function __TableUtil__Cell.new(name, opts)
return __TableUtil__Cell.__new(__TableUtil__CellType__Cell, name, opts)
end
-- [Function] Reset context
function __TableUtil__Cell:resetContext()
end
-- [Function] Render header
function __TableUtil__Cell:renderHeader(headerRow)
if self.headerColspan <= 0 then
return nil
end
local headerCell = headerRow:tag('th'):wikitext(self.name)
if self.headerClass then
headerCell:addClass(self.headerClass)
end
if self.headerColspan > 1 then
headerCell:attr('colspan', self.headerColspan)
end
if self.headerStyle then
headerCell:css(self.headerStyle)
end
return headerCell
end
-- [Function] Render footer
function __TableUtil__Cell:renderFooter(footerRow)
if self.headerColspan <= 0 then
return nil
end
local footerCell = footerRow:tag('td')
if self.footerClass then
footerCell:addClass(self.footerClass)
end
if self.headerColspan > 1 then
footerCell:attr('colspan', self.headerColspan)
end
return footerCell
end
-- [Function] Render
function __TableUtil__Cell:render(row)
local cell = row:tag('td')
if self.attributes then
cell:attr(self.attributes)
end
if self.cellClass then
cell:addClass(self.cellClass)
end
return cell
end
-- [Export]
tableutil.Cell = __TableUtil__Cell
-- =====================
-- type: ValueCell: Cell
-- =====================
local __TableUtil__CellType__ValueCell = 'value'
local __TableUtil__ValueCell = {
__typename = __TableUtil__CellType__ValueCell,
}
setmetatable(__TableUtil__ValueCell, { __index = __TableUtil__Cell })
-- [Constructor]
function __TableUtil__ValueCell.__new(typename, name, dataIndex, opts)
local obj = __TableUtil__Cell.__new(typename, name, opts)
obj.__cell__render = obj.render
obj.dataIndex = dataIndex
if type(opts) == 'table' then
obj.format = opts.format or __passthrough
else
obj.format = __passthrough
end
return setmetatable(obj, { __index = __TableUtil__ValueCell })
end
function __TableUtil__ValueCell.new(name, dataIndex, opts)
return __TableUtil__ValueCell.__new(__TableUtil__CellType__ValueCell, name, dataIndex, opts)
end
-- [Function] Render
function __TableUtil__ValueCell:render(row, dataset, i, datainfo)
local value = dataset[self.dataIndex]
local formattedValue = self.format(value)
local cell = self:__cell__render(row, dataset, i, datainfo)
:attr('data-sort-value', value)
:wikitext(formattedValue)
return cell
end
-- [Export]
tableutil.ValueCell = __TableUtil__ValueCell
-- =========================
-- type: RankCell: ValueCell
-- =========================
local __TableUtil__CellType__RankCell = 'rank'
local __TableUtil__RankCell = {
__typename = __TableUtil__CellType__RankCell,
}
setmetatable(__TableUtil__RankCell, { __index = __TableUtil__ValueCell })
-- [Constructor]
function __TableUtil__RankCell.new(name, dataIndex, descending)
local obj = __TableUtil__ValueCell.__new(__TableUtil__CellType__RankCell, name, dataIndex)
obj.currentRank = 0
obj.currentValue = -1
obj.descending = descending
return setmetatable(obj, { __index = __TableUtil__RankCell })
end
-- [Property] Is descending?
function __TableUtil__RankCell:isDescending()
return self.descending
end
-- [Function] Reset context
function __TableUtil__RankCell:resetContext(datainfo)
self.currentRank = 0
self.currentValue = -1
end
-- [Function] Render
function __TableUtil__RankCell:render(row, dataset, i)
local value = dataset[self.dataIndex]
if self.currentValue ~= value then
self.currentRank = i
self.currentValue = value
end
local cell = row:tag('th')
:attr('data-sort-value', value)
:wikitext(self.currentRank)
return cell
end
-- [Export]
tableutil.RankCell = __TableUtil__RankCell
-- ====================
-- type: LineCell: Cell
-- ====================
local __TableUtil__CellType__LineCell = 'line'
local __TableUtil__LineCell = {
__typename = __TableUtil__CellType__LineCell,
}
setmetatable(__TableUtil__LineCell, { __index = __TableUtil__ValueCell })
-- [Constructor]
function __TableUtil__LineCell.__new(typename, name, dataIndex, opts)
local obj = __TableUtil__Cell.__new(typename, name, opts)
obj.__cell__render = obj.render
obj.__cell__renderFooter = obj.renderFooter
obj.dataIndex = dataIndex
if type(opts) == 'table' then
obj.colorStops = opts.colorStops or '#A7D7F9'
if opts.gridEnabled then
obj.gridEnabled = opts.gridEnabled
else
obj.gridEnabled = true
end
obj.height = opts.height or 1.2
obj.minimumValue = opts.minimumValue or 0
obj.maximumRate = opts.maximumRate or 1.05
obj.preferredGridCount = opts.preferredGridCount or 4
else
obj.colorStops = '#A7D7F9'
obj.gridEnabled = true
obj.height = 1.2
obj.minimumValue = 0
obj.maximumRate = 1.05
obj.preferredGridCount = 4
end
obj._gridCount = 2
return setmetatable(obj, { __index = __TableUtil__LineCell })
end
function __TableUtil__LineCell.new(name, dataIndex, opts)
return __TableUtil__LineCell.__new(__TableUtil__CellType__LineCell, name, dataIndex, opts)
end
-- [Property] Height
function __TableUtil__LineCell:setHeight(value)
self.height = value
return self
end
-- [Function] Reset context
function __TableUtil__LineCell:resetContext(datainfo)
local target = datainfo[self.dataIndex]
local scale = scale.LinearScale.new()
:setClamp(true)
:setDomain({ self.minimumValue, self.maximumRate * target.maxValue })
:nice(self.preferredGridCount)
self._scale = scale
if self.gridEnabled then
self._ticks = scale:ticks(self.preferredGridCount)
end
end
-- [Function] Render footer
function __TableUtil__LineCell:renderFooter(footerRow)
local footerCell = self:__cell__renderFooter(footerRow)
if self.gridEnabled and footerCell then
footerCell
:addClass('st-axis')
:addClass(string.format('st-axis-%d', #self._ticks + 2))
local list = footerCell:tag('ul')
list:tag('li'):wikitext(self._scale.domain[1])
for _, tick in ipairs(self._ticks) do
list:tag('li'):wikitext(tick)
end
end
return footerCell
end
-- [Function] Render
function __TableUtil__LineCell:render(row, dataset, i, datainfo)
local gradientFormat
if type(self.colorStops) == 'table' then
if self.mixinValue then
gradientFormat = function(percentage, value)
percentage = 0.001 * aw.round(1000 * percentage)
return string.format(
'linear-gradient(to right,transparent,%s %s%%,%s %s%%,transparent %s%%)',
self.colorStops[1],
percentage,
self.colorStops[2],
percentage,
percentage)
end
else
gradientFormat = function(percentage, value)
percentage = 0.001 * aw.round(1000 * percentage)
return string.format(
'linear-gradient(to right,transparent,%s %s%%,%s %s%%,transparent %s%%)!important',
self.colorStops[1],
percentage,
self.colorStops[2],
percentage,
percentage)
end
end
else
if self.mixinValue then
gradientFormat = function(percentage, value)
percentage = 0.001 * aw.round(1000 * percentage)
return string.format(
'linear-gradient(to right,%s %s%%,transparent %s%%)',
self.colorStops,
percentage,
percentage)
end
else
gradientFormat = function(percentage, value)
percentage = 0.001 * aw.round(1000 * percentage)
return string.format(
'linear-gradient(to right,%s %s%%,transparent %s%%)!important',
self.colorStops,
percentage,
percentage)
end
end
end
local value = dataset[self.dataIndex]
local percentage = self._scale:scale(value)
local cell = self:__cell__render(row, dataset, i, datainfo)
:addClass('st-line')
:addClass(string.format('st-line-h%d', 10 * self.height))
if self.gridEnabled then
cell:addClass('st-grid')
:addClass(string.format('st-grid-%d', #self._ticks + 1))
end
cell:attr('data-sort-value', value)
:css('background-image', gradientFormat(percentage, value))
return cell
end
-- [Export]
tableutil.LineCell = __TableUtil__LineCell
-- =================
-- type: Value+XCell
-- =================
local function transformValueCell(superklass, klasstype)
local valuetype = string.format('value+%s', klasstype)
local valueKlass = {
__typename = valuetype,
}
setmetatable(valueKlass, { __index = superklass })
function valueKlass.new(name, dataIndex, opts)
local obj = superklass.__new(valuetype, name, dataIndex, opts)
obj.__super__render = obj.render
obj.__super__renderHeader = obj.renderHeader
obj.__super__renderFooter = obj.renderFooter
obj.mixinValue = true
if type(opts) == 'table' then
obj.format = opts.format or __passthrough
else
obj.format = __passthrough
end
return setmetatable(obj, { __index = valueKlass })
end
function valueKlass:render(row, dataset, i, datainfo)
local value = dataset[self.dataIndex]
local formattedValue = self.format(value)
local cell = self:__super__render(row, dataset, i, datainfo)
return cell:wikitext(formattedValue)
end
return valueKlass
end
-- [Export]
tableutil.LineValueCell = transformValueCell(__TableUtil__LineCell, __TableUtil__CellType__LineCell)
-- ===================
-- func: specifyUICell
-- ===================
function tableutil.specifyUICell(klasstype, renderFunction, propNames)
local specifictype = string.format('ui+%s', klasstype)
local specificKlass = {
__typename = specifictype,
}
setmetatable(specificKlass, { __index = __TableUtil__Cell })
function specificKlass.new(name, dataIndex, opts)
local obj = __TableUtil__Cell.__new(specifictype, name, opts)
obj.__cell__render = obj.render
obj.dataIndex = dataIndex
if propNames and opts then
for _, name in ipairs(propNames) do
obj[name] = opts[name]
end
end
return setmetatable(obj, { __index = specificKlass })
end
specificKlass.render = renderFunction
return specificKlass
end
-- =================
-- func: createTable
-- =================
function tableutil.createTable(dataset, metadata, opts)
local tbl = mw.html.create('table')
:addClass('numbertable')
:addClass('sortable')
:addClass('st')
:addClass('wikitable')
if opts and type(opts.tableClass) == 'string' then
tbl:addClass(opts.tableClass)
end
-- Build header
local headerRow = tbl:tag('tr'):addClass('row-sticky')
local sortIndex = 0
local isDesc = false
for _, m in ipairs(metadata) do
if m.typename == tableutil.RankCell.__typename then
sortIndex = m.dataIndex
isDesc = m:isDescending()
end
-- Render header
m:renderHeader(headerRow)
end
-- Sort data
if sortIndex ~= 0 then
local sortFunction
if isDesc then
sortFunction = function(a, b)
return a[sortIndex] > b[sortIndex]
end
else
sortFunction = function(a, b)
return a[sortIndex] < b[sortIndex]
end
end
table.sort(dataset, sortFunction)
end
-- Preprocess data
local datainfo = {}
for _, ary in ipairs(dataset) do
for key, d in pairs(ary) do
if type(d) == 'number' and d ~= math.huge then
if not datainfo[key] then
datainfo[key] = {
minValue = d,
maxValue = d,
}
else
if datainfo[key].minValue > d then
datainfo[key].minValue = d
end
if datainfo[key].maxValue < d then
datainfo[key].maxValue = d
end
end
end
end
end
-- Reset context
for _, m in ipairs(metadata) do
-- Reset context for building process
m:resetContext(datainfo)
end
-- Build cell
for i, d in ipairs(dataset) do
local row = tbl:tag('tr')
for k, m in ipairs(metadata) do
m:render(row, d, i, datainfo)
end
end
-- Build footer
local footerRow = tbl:tag('tr'):addClass('sortbottom')
for _, m in ipairs(metadata) do
-- Render footer
m:renderFooter(footerRow)
end
return tbl
end
-- =================
-- test: Simple test
-- =================
function tableutil.__test()
local metadata = {
tableutil.RankCell.new('', 1),
tableutil.ValueCell.new('Value', 1),
tableutil.LineCell.new('Line', 1, { cellClass = 'st-graph' }),
tableutil.LineCell.new('LineGradient', 1, { cellClass = 'st-graph', colorStops = { '#F8B3BC', '#F26D7D' }, height = 1.4 }),
tableutil.LineValueCell.new('LineValue', 2, { cellClass = 'st-graph st-textshadow' }),
}
local node = tableutil.createTable({{ 45, 110 }, { 40, 60 }, { 40, 120 }, { 50, 90 }}, metadata)
return tostring(node)
end
return tableutil