Skip to content

Instantly share code, notes, and snippets.

@zbryikt
Last active November 24, 2017 16:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zbryikt/4248542 to your computer and use it in GitHub Desktop.
Save zbryikt/4248542 to your computer and use it in GitHub Desktop.
Legislator Voting Result

立委投票結果產生器

幫你把立委在國會表決的結果畫成一目了然的圖表!

使用說明

  1. include lyvote.js ( generated from lyvote.ls )

  2. in your html do following

     <- $ document .ready                 # document.ready 後再呼叫 ..
     lyvote.render do                     #  .. 呼叫 lyvote.render, 傳入 config 物件:
       /* required argument */
       namelist: "voter.json"             # 立委名單網址(json) 如 mly-8.json.
       node: \body                        # 圖表容器 (selector, in string)
       vote: [
         <[丁守中 王育敏]>                # 贊成
         <[尤美女]>                       # 反對
         <[王惠美]>                       # 棄權
       ]
     
       /* optional argument */
       cx: 600                            # 圖表扇形圓心點座標
       cy: 500                            # 
       transform: "scale(0.8)"            # 圖表座標轉換. 主要用來縮放
       #seat-count: [12 16 18 22 24 21]   # 每列(共六列) 的坐位數. 沒給會自動產生
       #seat-mapping: (name) -> 0         # name -> seat-id mapping function
                                          #   string -> integer (0<=id<number of MLY)
    

範例頁

http://bl.ocks.org/4248542

html, body {
width: 100%;
height:100%
}
.mly-seat {
/*stroke: #f00*/
cursor: pointer;
}
.mly-vote {
font-family: arial;
}
.mly-name {
font-size: 15px;
cursor: pointer;
}
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="viewport" content="width=device-width"><title>立法委員投票結果</title><link rel="shortcut icon" href="favicon.ico"><script type="text/javascript" src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/md5.js"></script><script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script><script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script><link rel="stylesheet" type="text/css" href="index.css"><script type="text/javascript" src="lyvote.js"></script><script type="text/javascript" src="index.js"></script></head><body><div id="qsort" style="display:none;text-align:center;font-family:arial;position:absolute;top:400px;left:394px">Quick Sort Demonstration</div></body></html>
!!! 5
html(lang="en")
head
meta(charset='utf-8')
meta(http-equiv="X-UA-Compatible", content="IE=edge,chrome=1")
meta(name='viewport', content='width=device-width')
title 立法委員投票結果
link(rel="shortcut icon",href="favicon.ico")
script(type="text/javascript",src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/md5.js")
script(type="text/javascript",src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js")
script(type="text/javascript",src="http://d3js.org/d3.v3.min.js")
link(rel="stylesheet",type="text/css",href="index.css")
script(type="text/javascript",src="lyvote.js")
script(type="text/javascript",src="index.js")
body
#qsort(style="display:none;text-align:center;font-family:arial;position:absolute;top:400px;left:394px") Quick Sort Demonstration
(function(){
$(document).ready(function(){
var currentSort;
lyvote.render({
/* optional argument */
cx: 600,
cy: 500,
transform: "scale(0.8)"
/* required argument */,
namelist: "voter.json",
node: 'body',
vote: [['丁守中', '王育敏'], ['尤美女'], ['王惠美']]
});
currentSort = 0;
return setInterval(function(){
switch (currentSort) {
case 0:
lyvote.remap(lyvote.map.xorder);
break;
case 1:
lyvote.remap(lyvote.map.linear);
break;
case 2:
lyvote.remap(lyvote.map.strip);
break;
case 3:
lyvote.remap(lyvote.map.circular);
break;
case 4:
lyvote.remap(lyvote.map.random);
break;
case 5:
lyvote.map.qsort.init(lyvote);
$('#qsort').fadeIn();
lyvote.map.qsort.sort(lyvote) || lyvote.remap(lyvote.map.qsort);
break;
case 6:
lyvote.map.qsort.sort(lyvote) || lyvote.remap(lyvote.map.qsort);
break;
case 7:
lyvote.map.qsort.sort(lyvote) || lyvote.remap(lyvote.map.qsort);
break;
case 8:
lyvote.map.qsort.sort(lyvote) || lyvote.remap(lyvote.map.qsort);
break;
case 9:
lyvote.map.qsort.sort(lyvote) || lyvote.remap(lyvote.map.qsort);
break;
case 10:
$('#qsort').fadeOut();
lyvote.map.qsort.sort(lyvote) || lyvote.remap(lyvote.map.qsort);
}
return currentSort = (currentSort + 1) % 11;
}, 2000);
});
}).call(this);
<- $ document .ready
lyvote.render do
/* optional argument */
cx: 600
cy: 500 # chart center coordinate
transform: "scale(0.8)" # chart transformation
#seat-count: [12 16 18 22 24 21] # seat count in each row, totally 6 rows. auto-gen if not provided
#seat-mapping: (name) -> 0 # name -> seat-id mapping. ( seat-id range: [0 to 112] )
/* required argument */
namelist: "voter.json" # e.g., mly-8.json
node: \body # tag selector in string
vote: [
<[丁守中 王育敏]> # 贊成
<[尤美女]> # 反對
<[王惠美]> # 棄權
]
current-sort = 0
<- setInterval _, 2000
switch current-sort
|0 => lyvote.remap lyvote.map.xorder
|1 => lyvote.remap lyvote.map.linear
|2 => lyvote.remap lyvote.map.strip
|3 => lyvote.remap lyvote.map.circular
|4 => lyvote.remap lyvote.map.random
case 5
lyvote.map.qsort.init lyvote
$ \#qsort .fadeIn!
lyvote.map.qsort.sort(lyvote) || lyvote.remap lyvote.map.qsort
|6 => lyvote.map.qsort.sort(lyvote) || lyvote.remap lyvote.map.qsort
|7 => lyvote.map.qsort.sort(lyvote) || lyvote.remap lyvote.map.qsort
|8 => lyvote.map.qsort.sort(lyvote) || lyvote.remap lyvote.map.qsort
|9 => lyvote.map.qsort.sort(lyvote) || lyvote.remap lyvote.map.qsort
case 10
$ \#qsort .fadeOut!
lyvote.map.qsort.sort(lyvote) || lyvote.remap lyvote.map.qsort
current-sort := (current-sort + 1)%11
# class name for styling: .mly-seat, .mly-name, .mly-name-box
// Generated by LiveScript 1.3.1
var slice$ = [].slice;
this.lyvote = {
svg: null,
config: {
cx: 500,
cy: 500,
transform: "",
node: 'body'
},
colors: {
"KMT": '#55f',
"DPP": '#090',
"NSU": '#fbb',
"TSU": '#b26',
"PFP": '#f90',
"N/A": '#bbb',
'null': '#bbb'
},
map: {
qsort: {
idx: 0,
map: {},
order: null,
limit: 0,
init: function(r){
var len, res$, i$, it, ref$, len$, t, i, results$ = [];
len = r.config.seatCount.reduce(curry$(function(x$, y$){
return x$ + y$;
}));
this.limit = 0;
res$ = [];
for (i$ = 0; i$ < len; ++i$) {
it = i$;
res$.push(it);
}
this.order = res$;
res$ = [];
for (i$ = 0, len$ = (ref$ = this.order).length; i$ < len$; ++i$) {
it = ref$[i$];
res$.push([it, r.seatPosition(it)[0]]);
}
this.order = res$;
for (i$ = 0; i$ < len; ++i$) {
it = i$;
ref$ = [this.order[it], it + parseInt(Math.random() * (len - it))], t = ref$[0], i = ref$[1];
this.order[it] = this.order[i];
results$.push(this.order[i] = t);
}
return results$;
},
_sort: function(r, limit, level, L, R){
var pi, t, p, i, j;
if (level > limit) {
return;
}
if (L >= R) {
return;
}
pi = L + parseInt(Math.random() * (R - L + 1));
t = this.order[L];
this.order[L] = this.order[pi];
this.order[pi] = t;
p = this.order[L][1];
i = L + 1;
j = R;
while (i < j) {
while (this.order[i][1] <= p && i < j) {
i++;
}
while (this.order[j][1] > p) {
j--;
}
if (i >= j) {
break;
}
t = this.order[i];
this.order[i] = this.order[j];
this.order[j] = t;
}
t = this.order[L];
this.order[L] = this.order[j];
this.order[j] = t;
this._sort(r, limit, level + 1, L, j - 1);
return this._sort(r, limit, level + 1, j + 1, R);
},
sort: function(r){
return this._sort(r, this.limit++, 0, 0, this.order.length - 1);
},
indexOf: function(r, name){
var ref$, ref1$;
return this.order[(ref1$ = (ref$ = this.map)[name]) != null
? ref1$
: ref$[name] = this.idx++][0];
}
},
xorder: {
idx: 0,
map: {},
order: null,
indexOf: function(r, name){
var it, ref$, ref1$;
if (!this.order) {
this.order = (function(){
var i$, to$, fn$ = curry$(function(x$, y$){
return x$ + y$;
}), results$ = [];
for (i$ = 0, to$ = r.config.seatCount.reduce(fn$); i$ < to$; ++i$) {
it = i$;
results$.push([it, r.seatPosition(it)[0]]);
}
return results$;
}()).sort(function(a, b){
return a[1] - b[1];
});
}
return this.order[(ref1$ = (ref$ = this.map)[name]) != null
? ref1$
: ref$[name] = this.idx++][0];
}
},
strip: {
idx: 0,
map: {},
order: null,
indexOf: function(r, name){
var len, ref$, ref1$;
if (!this.order) {
len = r.config.seatCount.reduce(curry$(function(x$, y$){
return x$ + y$;
}));
this.order = (function(){
var i$, to$, results$ = [];
for (i$ = 0, to$ = len; i$ <= to$; i$ += 2) {
results$.push(i$);
}
return results$;
}()).concat((function(){
var i$, to$, results$ = [];
for (i$ = 1, to$ = len; i$ <= to$; i$ += 2) {
results$.push(i$);
}
return results$;
}()));
}
return this.order[(ref1$ = (ref$ = this.map)[name]) != null
? ref1$
: ref$[name] = this.idx++];
}
},
circular: {
idx: 0,
map: {},
order: null,
indexOf: function(r, name){
var it, ref$, ref1$;
if (!this.order) {
this.order = (function(){
var i$, to$, fn$ = curry$(function(x$, y$){
return x$ + y$;
}), results$ = [];
for (i$ = 0, to$ = r.config.seatCount.reduce(fn$); i$ < to$; ++i$) {
it = i$;
results$.push([
it, fn1$(
r.seatPosition(it))
]);
}
return results$;
function fn1$(it){
return [it[0] - r.config.cx, it[1]].reduce(function(a, b){
return a + Math.pow(b, 2);
}, 0);
}
}()).sort(function(a, b){
return a[1] - b[1];
});
}
return this.order[(ref1$ = (ref$ = this.map)[name]) != null
? ref1$
: ref$[name] = this.idx++][0];
}
},
linear: {
idx: 0,
map: {},
order: null,
indexOf: function(r, name){
var ref$, ref1$;
return (ref1$ = (ref$ = this.map)[name]) != null
? ref1$
: ref$[name] = this.idx++;
}
},
random: {
idx: 0,
map: {},
order: null,
indexOf: function(r, name){
var len, res$, i$, it, ref$, t, i, ref1$;
if (!this.order) {
len = r.config.seatCount.reduce(curry$(function(x$, y$){
return x$ + y$;
}));
res$ = [];
for (i$ = 0; i$ < len; ++i$) {
it = i$;
res$.push(it);
}
this.order = res$;
for (i$ = 0; i$ < len; ++i$) {
it = i$;
ref$ = [this.order[it], it + parseInt(Math.random() * (len - it))], t = ref$[0], i = ref$[1];
this.order[it] = this.order[i];
this.order[i] = t;
}
}
return this.order[(ref1$ = (ref$ = this.map)[name]) != null
? ref1$
: ref$[name] = this.idx++];
}
}
},
_idx: 0,
_map: {},
seatMappingDefault: function(name){
var ref$, ref1$;
return (ref1$ = (ref$ = this._map)[name]) != null
? ref1$
: ref$[name] = this._idx++;
},
seatMapping: function(name){
if (this.config.seatMapping) {
return this.config.seatMapping.indexOf.call(this.config.seatMapping, this, name);
} else {
return this.map.random.indexOf(this, name);
}
},
remap: function(mapObj){
var _pt, this$ = this;
this.config.seatMapping = mapObj;
_pt = function(it){
return this$.seatPosition(this$.seatMapping(it.name));
};
return this.seats.transition().duration(750).attr('transform', function(it){
return "translate(" + _pt(it)[0] + "," + _pt(it)[1] + ")";
});
},
seatPosition: function(idx){
var sc, res$, i$, len$, i, ret, ref$, row, len, j, m, v, fn$ = curry$(function(x$, y$){
return x$ + y$;
});
sc = this.config.seatCount;
res$ = [];
for (i$ = 0, len$ = sc.length; i$ < len$; ++i$) {
i = i$;
res$.push(slice$.call(sc, 0, i + 1 || 9e9).reduce(fn$));
}
sc = res$;
ret = sc.map(function(it){
return it - idx;
}).filter((function(it){
return it > 0;
}));
ref$ = [this.config.seatCount.length, ret.length], row = ref$[0], len = ref$[1];
ref$ = [row - len, ret[0] - 1, sc[row - len] - 1 - (len < row && sc[row - len - 1]) || 0], i = ref$[0], j = ref$[1], m = ref$[2];
v = [Math.cos(Math.PI * j / m), Math.sin(Math.PI * j / m)];
return [this.config.cx + v[0] * (160 + i * 60), this.config.cy - v[1] * (160 + i * 60)];
},
seats: null,
hName: {},
hParty: {},
generate: function(error, mlys){
var ref$, _sc, _sc_total, idx, i$, len$, mly, key$, i, names, j$, len1$, name, defs, imgs, panel, _pt, it, lockcell, this$ = this;
ref$ = [
{}, {
0: 0
}
], this.hName = ref$[0], this.hParty = ref$[1];
if (!this.config.seatCount) {
_sc = [0, 1, 2, 3, 4, 5].map(function(it){
return parseInt(2 * Math.PI * (it * 60 + 160));
});
_sc_total = _sc.reduce(curry$(function(x$, y$){
return x$ + y$;
}));
this.config.seatCount = _sc.map(function(it){
return Math.round(it * mlys.length / _sc_total);
});
}
idx = 0;
for (i$ = 0, len$ = mlys.length; i$ < len$; ++i$) {
mly = mlys[i$];
this.hName[mly.name] = {
name: mly.name,
vote: 0,
party: mly.party,
idx: idx++
};
(ref$ = this.hParty)[key$ = mly.party] == null && (ref$[key$] = this.hParty[0]++);
}
for (i$ = 0, len$ = (ref$ = this.config.vote).length; i$ < len$; ++i$) {
i = i$;
names = ref$[i$];
for (j$ = 0, len1$ = names.length; j$ < len1$; ++j$) {
name = names[j$];
this.hName[name].vote = i + 1;
}
}
this.svg = d3.select(this.config.node).append('svg').attr('width', '100%').attr('height', '100%');
defs = this.svg.selectAll('defs').data(mlys).enter().append('pattern').attr('id', function(it){
return 'defs_h' + this$.hName[it.name].idx;
}).attr('patternUnits', 'userSpaceOnUse').attr('x', 30).attr('y', 30).attr('width', 50).attr('height', 50);
imgs = defs.append('image').attr('x', 0).attr('y', 0).attr('width', 50).attr('height', 50).attr('transform', "scale(0.9)");
panel = this.svg.append('g').attr('transform', function(){
return this$.config.transform;
});
_pt = function(it){
return this$.seatPosition(this$.seatMapping(it.name));
};
this.seats = panel.selectAll('g.seat').data((function(){
var results$ = [];
for (it in this.hName) {
results$.push(this.hName[it]);
}
return results$;
}.call(this)).sort(function(a, b){
return this$.hParty[a.party] - this$.hParty[b.party];
})).enter().append('g').attr('transform', function(it){
return "translate(" + _pt(it)[0] + "," + _pt(it)[1] + ")";
});
lockcell = null;
this.seats.append('circle').attr('class', 'mly-seat').attr('r', 20).attr('fill', function(it){
return this$.colors[it.party];
}).style('opacity', function(it){
if (it.vote === 0) {
return 0.3;
} else {
return 1;
}
}).on('click', function(){
if (lockcell) {
d3.select(lockcell).attr('fill', function(it){
return this$.colors[it.party];
}).transition().duration(500).attr('transform', "scale(1)").attr('stroke', 'none').style('opacity', function(it){
if (it.vote === 0) {
return 0.3;
} else {
return 1;
}
});
}
if (lockcell === d3.event.target) {
return lockcell = null;
}
lockcell = d3.event.target;
return d3.select(d3.event.target).attr('fill', function(it){
return "url(#defs_h" + it.idx + ")";
}).transition().duration(500).attr('transform', "scale(2)").attr('stroke', function(it){
return this$.colors[it.party];
}).attr('stroke-width', '3px').style('opacity', 1);
});
this.seats.append('path').attr('d', function(it){
switch (it.vote) {
case 1:
return "M-12 0 L0 10 L11 -11";
case 2:
return "M-10,-10 L10,10 L0 0 L-10 10 L10 -10";
case 3:
return "M-10 0 L10 00";
case 9:
return "M15 0 A15 15 0 1 1 -15 0 A15 15 0 1 1 15 0";
default:
return "M0 0";
}
}).attr('stroke', function(it){
switch (it.vote) {
case 1:
return '#0b0';
case 2:
return '#b00';
case 3:
return '#999';
default:
return '#b00';
}
}).attr('stroke-width', '5px').attr('fill', 'none');
this.seats.append('rect').attr('class', 'mly-name-box').attr('x', -25).attr('y', 9).attr('width', 50).attr('height', 17).attr('rx', 10).attr('ry', 10).attr('fill', '#fff').style('opacity', 0.4);
return this.seats.append('text').attr('class', 'mly-name').attr('y', 22).attr('text-anchor', 'middle').text(function(it){
return it.name;
});
},
render: function(config){
var this$ = this;
import$(this.config, config);
return d3.json(config.namelist, function(error, json){
return this$.generate.call(this$, error, json);
});
}
};
function curry$(f, bound){
var context,
_curry = function(args) {
return f.length > 1 ? function(){
var params = args ? args.concat() : [];
context = bound ? context || this : this;
return params.push.apply(params, arguments) <
f.length && arguments.length ?
_curry.call(context, params) : f.apply(context, params);
} : f;
};
return _curry();
}
function import$(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}
@lyvote =
svg: null
config:
cx: 500
cy: 500
#seat-count: [12 16 18 22 24 21] now seat-count is auto-calculated
transform: ""
node: \body
colors:
"KMT": \#55f
"DPP": \#090
"NSU": \#fbb
"TSU": \#b26
"PFP": \#f90
"N/A": \#bbb
null: \#bbb
map:
qsort:
idx: 0
map: {}
order: null
limit: 0
init: (r) ->
len = r.config.seat-count.reduce (+)
@limit = 0
@order = [it for it til len]
@order = [[it,(r.seat-position it)0] for it in @order]
for it til len
[t,i] = [@order[it],it + parseInt Math.random! * (len - it)]
@order[it] = @order[i]
@order[i] = t
_sort: (r, limit, level, L, R) ->
if level>limit then return
if L>=R then return
pi = L + parseInt Math.random! * (R - L + 1 )
t = @order[L]
@order[L] = @order[pi]
@order[pi] = t
p = @order[L]1
i = L+1
j = R
while i < j
while @order[i]1<=p and i<j
i++
while @order[j]1>p
j--
if i>=j then break
t = @order[i]
@order[i] = @order[j]
@order[j] = t
t = @order[L]
@order[L] = @order[j]
@order[j] = t
@_sort(r, limit, level+1, L, j-1)
@_sort(r, limit, level+1, j+1, R)
sort: (r) ->
@_sort(r, @limit++, 0, 0, @order.length-1)
indexOf: (r, name) ->
@order[@map[name] ?= @idx++ ]0
xorder:
idx: 0
map: {}
order: null
indexOf: (r, name) ->
if !@order
@order = [[it,(r.seat-position it)0] for it til r.config.seat-count.reduce (+)].sort (a,b) -> a[1]-b[1]
return @order[@map[name] ?= @idx++ ]0
strip:
idx: 0
map: {}
order: null
indexOf: (r, name) ->
if !@order
len = r.config.seat-count.reduce (+)
@order = [0 to len by 2] ++ [1 to len by 2]
@order[@map[name] ?= @idx++ ]
circular:
idx: 0
map: {}
order: null
indexOf: (r, name) ->
if !@order
@order = [[it, (r.seat-position it)|> -> [it[0]-r.config.cx,it[1]] .reduce ((a,b)->a+b**2),0] for it til r.config.seat-count.reduce (+)].sort (a,b) -> a[1]-b[1]
return @order[@map[name] ?= @idx++ ]0
linear:
idx: 0
map: {}
order: null
indexOf: (r, name) ->
return @map[name] ?= @idx++
random:
idx: 0
map: {}
order: null
indexOf: (r, name) ->
if !@order
len = r.config.seat-count.reduce (+)
@order = [it for it til len]
for it til len
[t,i] = [@order[it],it + parseInt Math.random! * (len - it)]
@order[it] = @order[i]
@order[i] = t
return @order[@map[name] ?= @idx++ ]
_idx: 0
_map: {}
seat-mapping-default: (name) ->
@_map[name] ?= @_idx++
seat-mapping: (name) ->
if @config.seat-mapping then @config.seat-mapping.indexOf .call @config.seat-mapping,@,name
else @map.random.indexOf @,name
remap: (map-obj) ->
@config.seat-mapping = map-obj
_pt = ~> @seat-position @seat-mapping it.name
@seats.transition! .duration 750 .attr \transform ~> "translate(#{(_pt it)0},#{(_pt it)1})"
seat-position: (idx) ->
sc = @config.seat-count
sc = [sc[to i].reduce (+) for ,i in sc]
ret = (sc.map (-> it - idx) .filter (> 0))
[row, len] = [@config.seat-count.length, ret.length]
[i,j,m] = [row - len, ret[0]-1, sc[row - len] - 1 - (len<row && sc[row - len-1]) || 0 ]
v = [ Math.cos(Math.PI*j/m), Math.sin Math.PI*j/m ]
[ @config.cx + v[0]*(160+ i*60) , @config.cy - v[1]*(160 + i*60) ]
seats: null
h-name: {}
h-party: {}
generate: (error, mlys) ->
[@h-name,@h-party] = [{} {0:0}]
if !@config.seat-count
_sc = [0 til 6].map -> parseInt 2*Math.PI*(it*60+160)
_sc_total = _sc.reduce (+)
@config.seat-count = _sc.map -> Math.round it*mlys.length/_sc_total
idx = 0
for mly in mlys
@h-name[mly.name] =
name: mly.name
vote: 0
party: mly.party
idx: idx++
@h-party[mly.party] ?= @h-party[0]++
for names,i in @config.vote
for name in names
@h-name[name].vote = i+1
@svg = d3.select @config.node .append \svg
.attr \width \100%
.attr \height \100%
defs = @svg.selectAll \defs .data mlys .enter! .append \pattern
.attr \id ~> \defs_h + @h-name[it.name].idx
.attr \patternUnits \userSpaceOnUse
.attr \x 30
.attr \y 30
.attr \width 50
.attr \height 50
#.attr \xlink:href -> "http://avatars.io/50a65bb26e293122b0000073/#{CryptoJS.MD5('MLY/'+it.name).toString()}?size=small"
imgs = defs.append \image
.attr \x 0
.attr \y 0
.attr \width 50
.attr \height 50
.attr \transform "scale(0.9)"
panel = @svg.append \g
.attr \transform ~> @config.transform
_pt = ~> @seat-position @seat-mapping it.name
@seats = panel.selectAll \g.seat
.data [@h-name[it] for it of @h-name].sort( (a,b) ~>
@h-party[a.party] - @h-party[b.party]) .enter! .append \g
.attr \transform ~> "translate(#{(_pt it)0},#{(_pt it)1})"
lockcell = null
@seats.append \circle
.attr \class \mly-seat
.attr \r 20
.attr \fill ~> @colors[it.party]
.style \opacity ~> if it.vote == 0 then 0.3 else 1
.on \click ~>
if lockcell
d3.select lockcell .attr \fill ~> @colors[it.party]
.transition! .duration 500
.attr \transform "scale(1)"
.attr \stroke \none
.style \opacity ~> if it.vote == 0 then 0.3 else 1
if lockcell == d3.event.target
return lockcell := null
lockcell := d3.event.target
d3.select d3.event.target .attr \fill -> "url(\#defs_h#{it.idx})"
.transition! .duration 500
.attr \transform "scale(2)"
.attr \stroke ~> @colors[it.party]
.attr \stroke-width \3px
.style \opacity 1
@seats.append \path
.attr \d ~> switch it.vote
|1 => "M-12 0 L0 10 L11 -11"
|2 => "M-10,-10 L10,10 L0 0 L-10 10 L10 -10"
|3 => "M-10 0 L10 00"
|9 => "M15 0 A15 15 0 1 1 -15 0 A15 15 0 1 1 15 0"
|otherwise => "M0 0"
.attr \stroke ~> switch it.vote
|1 => \#0b0
|2 => \#b00
|3 => \#999
|otherwise => \#b00
.attr \stroke-width \5px
.attr \fill \none
@seats.append \rect
.attr \class \mly-name-box
.attr \x -25
.attr \y 9
.attr \width 50
.attr \height 17
.attr \rx 10
.attr \ry 10
.attr \fill \#fff
.style \opacity 0.4
@seats.append \text
.attr \class \mly-name
.attr \y 22
.attr \text-anchor \middle
.text (.name)
render: (config) ->
@config <<< config
d3.json config.namelist, (error, json) ~>
@generate.call @, error, json
all:
jade index.jade
livescript -cp index.ls > index.js
livescript -cp lyvote.ls > lyvote.js
[ { "name": "丁守中",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPE", 1 ] },
{ "name": "孔文吉",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "aborigine", "highland" ] },
{ "name": "尤美女",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "王廷升",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "HUA", 0 ] },
{ "name": "王育敏",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "王金平",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "王進士",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "PIF", 2 ] },
{ "name": "王惠美",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "CHA", 1 ] },
{ "name": "田秋堇",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "江啟臣",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TXG", 8 ] },
{ "name": "江惠貞",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPQ", 7 ] },
{ "name": "何欣純",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TXG", 7 ] },
{ "name": "吳宜臻",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "吳育仁",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "吳育昇",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPQ", 1 ] },
{ "name": "吳秉叡",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "呂玉玲",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TAO", 5 ] },
{ "name": "呂學樟",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "HSZ", 0 ] },
{ "name": "李昆澤",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "KHH", 6 ] },
{ "name": "李俊俋",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "CYI", 0 ] },
{ "name": "李桐豪",
"party": "PFP",
"caucus": "PFP",
"constuiency": [ "proportional" ] },
{ "name": "李貴敏",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "李慶華",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPQ", 12 ] },
{ "name": "李應元",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "李鴻鈞",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPQ", 4 ] },
{ "name": "邱文彥",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "邱志偉",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "KHH", 2 ] },
{ "name": "邱議瑩",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "KHH", 1 ] },
{ "name": "林世嘉",
"party": "TSU",
"caucus": "TSU",
"constuiency": [ "proportional" ] },
{ "name": "林正二Komod",
"party": "PFP",
"caucus": "PFP",
"constuiency": [ "aborigine", "lowland" ] },
{ "name": "林佳龍",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TXG", 6 ] },
{ "name": "林岱樺",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "KHH", 4 ] },
{ "name": "林明溱",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "NAN", 2 ] },
{ "name": "林郁方",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPE", 5 ] },
{ "name": "林國正",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "KHH", 9 ] },
{ "name": "林淑芬",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TPQ", 2 ] },
{ "name": "林滄敏",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "CHA", 2 ] },
{ "name": "林德福",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPQ", 9 ] },
{ "name": "林鴻池",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPQ", 6 ] },
{ "name": "姚文智",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TPE", 2 ] },
{ "name": "柯建銘",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "段宜康",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "洪秀柱",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "紀國棟",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "孫大千",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TAO", 6 ] },
{ "name": "徐少萍",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "徐欣瑩",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "HSQ", 0 ] },
{ "name": "徐耀昌",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "MIA", 2 ] },
{ "name": "翁重鈞",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "CYQ", 1 ] },
{ "name": "陳其邁",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "陳明文",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "CYQ", 2 ] },
{ "name": "陳亭妃",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TNN", 3 ] },
{ "name": "陳唐山",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TNN", 5 ] },
{ "name": "陳根德",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TAO", 1 ] },
{ "name": "陳淑慧",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "陳雪生",
"party": null,
"caucus": null,
"constuiency": [ "LJF", 0 ] },
{ "name": "陳超明",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "MIA", 1 ] },
{ "name": "陳節如",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "陳碧涵",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "陳歐珀",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "ILA", 0 ] },
{ "name": "陳學聖",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TAO", 3 ] },
{ "name": "陳鎮湘",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "馬文君",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "NAN", 1 ] },
{ "name": "高志鵬",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TPQ", 3 ] },
{ "name": "高金素梅",
"party": "NSU",
"caucus": null,
"constuiency": [ "aborigine", "highland" ] },
{ "name": "張嘉郡",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "YUN", 1 ] },
{ "name": "張慶忠",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPQ", 8 ] },
{ "name": "張曉風",
"party": "PFP",
"caucus": "PFP",
"constuiency": [ "proportional" ] },
{ "name": "許忠信",
"party": "TSU",
"caucus": "TSU",
"constuiency": [ "proportional" ] },
{ "name": "許添財",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TNN", 4 ] },
{ "name": "許智傑",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "KHH", 8 ] },
{ "name": "曾巨威",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "葉宜津",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TNN", 1 ] },
{ "name": "費鴻泰",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPE", 7 ] },
{ "name": "黃文玲",
"party": "TSU",
"caucus": "TSU",
"constuiency": [ "proportional" ] },
{ "name": "黃志雄",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPQ", 5 ] },
{ "name": "黃昭順",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "KHH", 3 ] },
{ "name": "黃偉哲",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TNN", 2 ] },
{ "name": "楊玉欣",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "楊應雄",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "JME", 0 ] },
{ "name": "楊曜",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "PEN", 0 ] },
{ "name": "楊瓊瓔",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TXG", 3 ] },
{ "name": "楊麗環",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TAO", 4 ] },
{ "name": "詹凱臣",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "foreign" ] },
{ "name": "廖正井",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TAO", 2 ] },
{ "name": "廖國棟",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "aborigine", "lowland" ] },
{ "name": "管碧玲",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "KHH", 5 ] },
{ "name": "蔡正元",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPE", 4 ] },
{ "name": "蔡其昌",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TXG", 1 ] },
{ "name": "蔡煌瑯",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "蔡錦隆",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TXG", 4 ] },
{ "name": "蔣乃辛",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPE", 6 ] },
{ "name": "趙天麟",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "KHH", 7 ] },
{ "name": "鄭天財Sra.Kacaw",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "aborigine", "lowland" ] },
{ "name": "鄭汝芬",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "CHA", 3 ] },
{ "name": "鄭麗君",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "劉建國",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "YUN", 2 ] },
{ "name": "劉櫂豪",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "TTT", 0 ] },
{ "name": "潘孟安",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "PIF", 3 ] },
{ "name": "潘維剛",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "盧秀燕",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TXG", 5 ] },
{ "name": "盧嘉辰",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPQ", 10 ] },
{ "name": "蕭美琴",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "薛凌",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "proportional" ] },
{ "name": "賴士葆",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPE", 8 ] },
{ "name": "謝國樑",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "KEE", 0 ] },
{ "name": "魏明谷",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "CHA", 4 ] },
{ "name": "簡東明",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "aborigine", "highland" ] },
{ "name": "顏清標",
"party": "NSU",
"caucus": null,
"constuiency": [ "TXG", 2 ] },
{ "name": "羅明才",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPQ", 11 ] },
{ "name": "羅淑蕾",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "TPE", 3 ] },
{ "name": "蘇清泉",
"party": "KMT",
"caucus": "KMT",
"constuiency": [ "proportional" ] },
{ "name": "蘇震清",
"party": "DPP",
"caucus": "DPP",
"constuiency": [ "PIF", 1 ] } ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment