151 lines
No EOL
4.4 KiB
JavaScript
151 lines
No EOL
4.4 KiB
JavaScript
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm"
|
|
|
|
import * as Plot from "https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6/+esm";
|
|
|
|
function clean_poll_data(data, rel_start_time) {
|
|
const {start_date, end_date, question, answers, votes} = data;
|
|
|
|
const num_votes = votes.length;
|
|
|
|
const totals = answers.map(a => 0);
|
|
totals.push(0);
|
|
|
|
const start_time = new Date(start_date);
|
|
const end_time = new Date(end_date);
|
|
|
|
answers.forEach((a,i) => {
|
|
votes.splice(0,0,{time: start_time, answer: i});
|
|
})
|
|
|
|
votes.forEach((v,i) => {
|
|
v.time = new Date(v.time);
|
|
v.total = totals[v.answer];
|
|
v.answer_name = answers[v.answer].answer;
|
|
totals[v.answer] += 1;
|
|
});
|
|
|
|
const last_vote_time = votes[votes.length-1].time;
|
|
const duration = last_vote_time - start_time;
|
|
|
|
answers.forEach((a,i) => {
|
|
votes.push({time: last_vote_time, answer: i, total: totals[i]-1, answer_name: answers[i].answer});
|
|
})
|
|
|
|
votes.forEach(v => {v.time = v.time - start_time + rel_start_time});
|
|
|
|
return {start_date, end_date, duration, question, answers, votes, last_vote_time};
|
|
|
|
}
|
|
|
|
async function plot_poll(ids, container) {
|
|
const reqs = await Promise.all(ids.map(id => fetch(`https://aperiodical.com/wp-json/wp-polls/v3/results/${id}`)));
|
|
const datas = await Promise.all(reqs.map(r => r.json()));
|
|
console.log(datas);
|
|
let all_votes = [];
|
|
const rel_start_time = 60*60*8 * 1000;
|
|
let max_duration = 0;
|
|
let title = '';
|
|
let num_answers = 0;
|
|
for(let data of datas) {
|
|
const {votes, answers, question, duration, last_vote_time} = clean_poll_data(data, rel_start_time);
|
|
votes.forEach(v => v.answer += num_answers);
|
|
title = question;
|
|
all_votes = all_votes.concat(votes);
|
|
max_duration = Math.max(duration, max_duration);
|
|
num_answers += answers.length;
|
|
}
|
|
console.table(all_votes);
|
|
|
|
container.innerHTML = '';
|
|
|
|
const link = document.createElement('link');
|
|
link.rel = 'stylesheet';
|
|
link.href = 'poll.css';
|
|
container.append(link);
|
|
|
|
const header = document.createElement('h2');
|
|
header.textContent = title;
|
|
container.append(header);
|
|
|
|
const plot = Plot.plot({
|
|
y: {
|
|
label: 'Votes',
|
|
grid: true,
|
|
},
|
|
x: {
|
|
label: 'Time',
|
|
tickFormat: t => {
|
|
t /= 1000;
|
|
const seconds = t % 60;
|
|
t = (t-seconds)/60;
|
|
const minutes = t % 60;
|
|
t = (t-minutes)/60;
|
|
const hours = t % 24;
|
|
return `${hours.toString().padStart(2,'0')}:${minutes.toString().padStart(2,'0')}`;
|
|
}
|
|
},
|
|
marks: [
|
|
Plot.line([{time: rel_start_time, total: 0}, {time: max_duration + rel_start_time, total: 0}],{x:'time', y:'total'}),
|
|
Plot.lineY(all_votes, {x: "time", y: "total", z: "answer", stroke: 'answer_name'}),
|
|
Plot.text(all_votes, Plot.selectLast({x:'time', y: 'total', z: 'answer', text: 'answer_name', textAnchor: 'end', dx: -6}))
|
|
]
|
|
})
|
|
container.append(plot);
|
|
}
|
|
|
|
class PollPlotElement extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.attachShadow({mode:'open'});
|
|
}
|
|
|
|
static observedAttributes = ['pollids'];
|
|
|
|
attributeChangedCallback() {
|
|
this.make_plot();
|
|
}
|
|
|
|
make_plot() {
|
|
const poll_ids = this.getAttribute('pollids').split(',').map(n=>parseInt(n));
|
|
if(poll_ids.some(id=>isNaN(id))) {
|
|
return;
|
|
}
|
|
plot_poll(poll_ids, this.shadowRoot);
|
|
}
|
|
}
|
|
|
|
customElements.define('poll-plot', PollPlotElement);
|
|
|
|
(async () => {
|
|
const polls = await (await fetch('https://aperiodical.com/wp-json/wp-polls/v3/polls')).json();
|
|
window.polls = polls;
|
|
polls.sort((a,b) => (new Date(b.opens)) - (new Date(a.opens)));
|
|
const params = new URLSearchParams(location.search);
|
|
let pollids, year;
|
|
if(params.has('year')) {
|
|
year = params.get('year');
|
|
console.log(year);
|
|
pollids = polls.filter(p => (new Date(p.opens)).getFullYear()==year).map(p=>p.id);
|
|
} else {
|
|
if(params.has('pollid')) {
|
|
pollids = params.get('pollid');
|
|
} else {
|
|
pollids = polls[0].id;
|
|
}
|
|
}
|
|
document.querySelector('poll-plot').setAttribute('pollids',pollids);
|
|
|
|
const polls_list = document.getElementById('other-matches');
|
|
for(let p of polls) {
|
|
const li = document.createElement('li');
|
|
const a = document.createElement('a');
|
|
a.href = `?pollid=${p.id}`;
|
|
if(pollids.includes(p.id)) {
|
|
a.setAttribute('aria-current', 'page');
|
|
}
|
|
const opens = new Date(p.opens);
|
|
a.textContent = `${opens.getFullYear()} - ${p.question}`;
|
|
li.append(a);
|
|
polls_list.append(li);
|
|
}
|
|
})(); |