| rev | line source | 
| bsw@1045 | 1 function util.initiative_pie(initiative, d, gap) | 
| bsw@1045 | 2   if not initiative.issue.closed or not initiative.admitted then | 
| bsw@1045 | 3     return | 
| bsw@1045 | 4   end | 
| bsw@1045 | 5 | 
| bsw@1045 | 6   if initiative.issue.voter_count == 0 or initiative.positive_votes == nil or initiative.negative_votes == nil then | 
| bsw@1045 | 7     return | 
| bsw@1045 | 8   end | 
| bsw@1045 | 9 | 
| bsw@1045 | 10   local first_preference_votes = initiative.first_preference_votes | 
| bsw@1045 | 11 | 
| bsw@1045 | 12   local d = d or 100 | 
| bsw/jbe@1309 | 13   local gap = 2 | 
| bsw@1045 | 14 | 
| bsw@1045 | 15   local r = d/2 | 
| bsw@1045 | 16   local r_circle = r - gap | 
| bsw@1045 | 17 | 
| bsw@1045 | 18   local function circle(p) | 
| bsw@1045 | 19     return | 
| bsw@1045 | 20       gap + 2 * r_circle * ( 1 + math.sin( 2 * math.pi * p ) ) / 2, | 
| bsw@1045 | 21       gap + 2 * r_circle * ( 1 - math.cos( 2 * math.pi * p ) ) / 2 | 
| bsw@1045 | 22   end | 
| bsw@1045 | 23 | 
| bsw@1045 | 24   local function getpath(start, stop) | 
| bsw@1045 | 25     local start_x, start_y = circle(start) | 
| bsw@1045 | 26     local stop_x, stop_y = circle(stop) | 
| bsw@1045 | 27     local large = stop - start > 0.5 and "1" or "0" | 
| bsw@1045 | 28     return "M" .. r .. "," .. r .. " " | 
| bsw@1045 | 29         .. "L" .. start_x .. ",".. start_y .. " " .. " " | 
| bsw@1045 | 30         .. "A" .. r_circle .. "," .. r_circle .. " 0 " .. large .. ",1 " .. stop_x .. "," .. stop_y .. " " | 
| bsw@1045 | 31         .. "z" | 
| bsw@1045 | 32   end | 
| bsw@1045 | 33 | 
| bsw@1045 | 34   local function uniPie(color, content) | 
| bsw@1045 | 35     ui.tag { | 
| bsw@1045 | 36       tag = "svg", | 
| bsw@1045 | 37       attr = { | 
| bsw@1045 | 38         class = "initiative_pie", | 
| bsw@1045 | 39         width = d .. "px", | 
| bsw@1045 | 40         height = d .. "px", | 
| bsw@1045 | 41       }, | 
| bsw@1045 | 42       content = function () | 
| bsw@1045 | 43         ui.tag { tag = "circle", attr = { | 
| bsw@1045 | 44           cx=r, cy=r, r=r_circle, fill = color, stroke = "#fff", ["stroke-width"] = "2" | 
| bsw@1045 | 45         }, content = function () ui.tag { tag = "title", content = content } end  } | 
| bsw@1045 | 46       end | 
| bsw@1045 | 47     } | 
| bsw@1045 | 48   end | 
| bsw@1045 | 49 | 
| bsw@1045 | 50   local function piePiece(path, fill, content) | 
| bsw@1045 | 51     ui.tag { | 
| bsw@1045 | 52       tag = "path", | 
| bsw@1045 | 53       attr = { | 
| bsw@1045 | 54         d = path, | 
| bsw@1045 | 55         fill = fill, | 
| bsw@1045 | 56         stroke = "#fff", | 
| bsw@1045 | 57         ["stroke-width"] = "2", | 
| bsw@1045 | 58         ["stroke-linecap"] = "butt" | 
| bsw@1045 | 59       }, | 
| bsw@1045 | 60       content = function () | 
| bsw@1045 | 61         ui.tag { | 
| bsw@1045 | 62           tag = "title", | 
| bsw@1045 | 63           content = content | 
| bsw@1045 | 64         } | 
| bsw@1045 | 65       end | 
| bsw@1045 | 66     } | 
| bsw@1045 | 67   end | 
| bsw@1045 | 68 | 
| bsw@1045 | 69   local function pie(args) | 
| bsw@1045 | 70     local offset = args.offset or 0 | 
| bsw@1045 | 71     local list = {} | 
| bsw@1045 | 72     local sum = 0 | 
| bsw@1045 | 73     for i, element in ipairs(args) do | 
| bsw@1045 | 74       element.start = sum + offset | 
| bsw@1045 | 75       list[#list+1] = element | 
| bsw@1045 | 76       sum = sum + element.value | 
| bsw@1045 | 77     end | 
| bsw@1045 | 78 | 
| bsw@1045 | 79     for i, element in ipairs(list) do | 
| bsw@1045 | 80       if element.value == sum then | 
| bsw@1045 | 81         uniPie(element.fill, _(element.label, { count = element.value } )) | 
| bsw@1045 | 82         return | 
| bsw@1045 | 83       end | 
| bsw@1045 | 84     end | 
| bsw@1045 | 85     ui.tag { | 
| bsw@1045 | 86       tag = "svg", | 
| bsw@1045 | 87       attr = { | 
| bsw@1045 | 88         class = "initiative_pie", | 
| bsw@1045 | 89         width = d .. "px", | 
| bsw@1045 | 90         height = d .. "px" | 
| bsw@1045 | 91       }, | 
| bsw@1045 | 92       content = function () | 
| bsw@1045 | 93         table.sort(list, function (a, b) | 
| bsw@1045 | 94           return a.value < b.value | 
| bsw@1045 | 95         end ) | 
| bsw@1045 | 96         for i, element in ipairs(list) do | 
| bsw@1045 | 97           local path = getpath(element.start / sum, (element.start + element.value) / sum) | 
| bsw@1045 | 98           local content = _(element.label, { count = element.value }) | 
| bsw@1045 | 99           piePiece(path, element.fill, content) | 
| bsw@1045 | 100         end | 
| bsw@1045 | 101       end | 
| bsw@1045 | 102     } | 
| bsw@1045 | 103   end | 
| bsw@1045 | 104 | 
| bsw@1045 | 105   local yes1 = first_preference_votes | 
| bsw@1045 | 106   local yes = initiative.positive_votes - first_preference_votes | 
| bsw@1045 | 107   local neutral = initiative.issue.voter_count - initiative.positive_votes - initiative.negative_votes | 
| bsw@1045 | 108   local no = initiative.negative_votes | 
| bsw@1045 | 109 | 
| bsw@1045 | 110   local sum = yes1 + yes + neutral + no | 
| bsw@1045 | 111 | 
| bsw@1045 | 112   local q = initiative.issue.policy.direct_majority_num / initiative.issue.policy.direct_majority_den | 
| bsw@1045 | 113 | 
| bsw@1045 | 114 | 
| bsw@1045 | 115   local maxrot = sum * 7 / 12 - no | 
| bsw@1045 | 116 | 
| bsw@1045 | 117   local offset = 0 | 
| bsw@1045 | 118 | 
| bsw@1045 | 119   if maxrot > 0 then | 
| bsw@1045 | 120     offset = math.min ( | 
| bsw@1045 | 121       maxrot, | 
| bsw@1045 | 122       no * ( 1 / ( 1 / q - 1 ) -1 ) / 2 | 
| bsw@1045 | 123     ) | 
| bsw@1045 | 124   end | 
| bsw@1045 | 125 | 
| bsw@1045 | 126   pie{ | 
| bsw@1045 | 127     { value = yes1,    fill = "#0a0", label = _"#{count} Yes, first choice" }, | 
| bsw@1045 | 128     { value = yes,     fill = "#6c6", label = _"#{count} Yes, alternative choice" }, | 
| bsw@1045 | 129     { value = neutral, fill = "#ccc", label = _"#{count} Neutral" }, | 
| bsw@1045 | 130     { value = no,      fill = "#c00", label = _"#{count} No" }, | 
| bsw@1045 | 131     offset = - offset | 
| bsw@1045 | 132   } | 
| bsw@1045 | 133 | 
| bsw/jbe@1309 | 134 end |