|
| 1 | +local a = require('Module:ACandy').a |
| 2 | +local getArgs = require('Module:Arguments').getArgs |
| 3 | + |
| 4 | +local p = {} |
| 5 | + |
| 6 | +local function deg2rad(d) return d * math.pi / 180 end |
| 7 | + |
| 8 | +local function makeRings(max) |
| 9 | + local step = 50 / max |
| 10 | + local parts = {} |
| 11 | + for i = 1, max do |
| 12 | + local pct = i * step |
| 13 | + local style = "radial-gradient(circle at center, rgba(127,127,127,0.1) %.2f%%, rgba(0,0,0,0) %.2f%%)" |
| 14 | + table.insert(parts, string.format(style, pct-0.3, pct+0.3)) |
| 15 | + end |
| 16 | + return table.concat(parts, ",") |
| 17 | +end |
| 18 | + |
| 19 | +function p.main(frame) |
| 20 | + local args = getArgs(frame, {removeBlanks = true}) |
| 21 | + local maxValue = tonumber(args.max) or 5 |
| 22 | + local width = args.width or "500px" |
| 23 | + |
| 24 | + local names, values = {}, {} |
| 25 | + for _, arg in ipairs(args) do |
| 26 | + local i, _ = string.find(arg, "::"); |
| 27 | + local key, value; |
| 28 | + if i then |
| 29 | + key = string.sub(arg, 1, i - 1); |
| 30 | + value = string.sub(arg, i + 2); |
| 31 | + local num = tonumber(value) |
| 32 | + if num then |
| 33 | + table.insert(names, key) |
| 34 | + table.insert(values, num) |
| 35 | + end |
| 36 | + end |
| 37 | + end |
| 38 | + |
| 39 | + local n = #names |
| 40 | + if n < 3 then |
| 41 | + return 'Error: Need at least 3 axes.' |
| 42 | + end |
| 43 | + |
| 44 | + local maxR, center = 35, 50 -- percentages |
| 45 | + local points, markers, labels, spokes = {}, {}, {}, {} |
| 46 | + |
| 47 | + for i=1,n do |
| 48 | + -- Ensure there is always one angled to point to the top |
| 49 | + local angle = - 90 - (i-1) * (360/n) |
| 50 | + local r = (values[i] / maxValue) * maxR |
| 51 | + local x = center + r * math.cos(deg2rad(angle)) |
| 52 | + local y = center + r * math.sin(deg2rad(angle)) |
| 53 | + table.insert(points, string.format('%.3f%% %.3f%%', x, y)) |
| 54 | + |
| 55 | + -- marker |
| 56 | + table.insert(markers, a.div { |
| 57 | + style = string.format( |
| 58 | + 'position:absolute;left:%.3f%%;top:%.3f%%;' .. |
| 59 | + 'width:2%%;height:2%%;margin:-1%% 0 0 -1%%;' .. |
| 60 | + 'border-radius:50%%;background:#377dff;border:0.6%% solid #fff', |
| 61 | + x, y |
| 62 | + ) |
| 63 | + }) |
| 64 | + |
| 65 | + -- label (slightly beyond maxR) |
| 66 | + -- X-axis needs to be further away since text spans horizontally |
| 67 | + local lx = center + maxR * 1.3 * math.cos(deg2rad(angle)) |
| 68 | + local ly = center + maxR * 1.2 * math.sin(deg2rad(angle)) |
| 69 | + table.insert(labels, a.div { |
| 70 | + style = string.format( |
| 71 | + 'position:absolute;left:%.3f%%;top:%.3f%%;' .. |
| 72 | + 'transform:translate(-50%%,-50%%);' .. |
| 73 | + 'font-size: larger', |
| 74 | + lx, ly |
| 75 | + ), |
| 76 | + names[i] |
| 77 | + }) |
| 78 | + |
| 79 | + -- spoke |
| 80 | + table.insert(spokes, a.div { |
| 81 | + style = string.format( |
| 82 | + 'position:absolute;left:50%%;top:50%%;' .. |
| 83 | + 'width:0.6%%;height:%d%%;background:#cfcfcf;' .. |
| 84 | + 'transform-origin:50%% 0%%;transform:translateX(-50%%) rotate(%.1fdeg);', |
| 85 | + maxR, - angle + 90 |
| 86 | + ) |
| 87 | + }) |
| 88 | + end |
| 89 | + |
| 90 | + -- polygon fill |
| 91 | + local poly = a.div { |
| 92 | + style = string.format( |
| 93 | + 'position:absolute;left:0;top:0;width:100%%;height:100%%;' .. |
| 94 | + 'clip-path:polygon(%s);' .. |
| 95 | + 'background:linear-gradient(135deg,rgba(55,125,255,0.28),rgba(55,125,255,0.18));' .. |
| 96 | + 'border:0.6%% solid rgba(55,125,255,0.5);border-radius:2%%;', |
| 97 | + table.concat(points, ',') |
| 98 | + ) |
| 99 | + } |
| 100 | + |
| 101 | + local rings = makeRings(maxValue); |
| 102 | + |
| 103 | + return a.div { |
| 104 | + style = string.format( |
| 105 | + 'width:%s;max-width:100%%;position:relative;' .. |
| 106 | + 'aspect-ratio : 1 / 1;' .. |
| 107 | + 'background: %s; ' .. |
| 108 | + 'border-radius:2%%;box-shadow:0 0.3%% 0.6%% rgba(0,0,0,0.06);', |
| 109 | + width, rings |
| 110 | + ), |
| 111 | + -- center dot |
| 112 | + a.div { style = 'position:absolute;left:50%;top:50%;width:1.8%;height:1.8%;margin:-0.9% 0 0 -0.9%;border-radius:50%;background:#666;opacity:0.8' }, |
| 113 | + -- spokes, labels, polygon, markers |
| 114 | + spokes, |
| 115 | + labels, |
| 116 | + poly, |
| 117 | + markers |
| 118 | + }; |
| 119 | +end |
| 120 | + |
| 121 | +return p |
0 commit comments