first commit
This commit is contained in:
commit
941d060004
5 changed files with 188 additions and 0 deletions
151
script.js
Normal file
151
script.js
Normal file
|
@ -0,0 +1,151 @@
|
|||
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);
|
||||
}
|
||||
})();
|
Loading…
Add table
Add a link
Reference in a new issue