import * as d3 from 'd3'; import { repr } from '../utilities/formatter'; // d3js module for module04: poll generator export default () => { // defaults const options = { width: 475, height: 500, radius: 10, data: [], pollindex: 0, setData: () => {} // eslint-disable-line no-empty-function }; // start const poll = selection => { const svg = selection.select('svg'); const scores = options.data.map(distribution => distribution.score); const xScale = d3.scaleLinear().domain([ 0, 100 ]).range([ 0, options.width ]); const bisect = d3.bisector(d => d.cumul).left; // reset everything const reset = () => { svg.select('.counter').text(''); svg.selectAll('rect.diff, rect.election').transition().duration(1000).attr('width', 0); svg.selectAll('text.difftext, text.result').text(''); svg.selectAll('rect.poll').transition().duration(1000).attr('width', 0); svg.selectAll('text.polltext').text(''); svg.selectAll('circle').transition() .duration(2000) .attr('cy', () => (options.height * Math.random())) .attr('cx', () => (options.width * Math.random())) .attr('fill-opacity', 0.2); }; // generate new poll const generatepoll = pollind => { if (options.pollindex === 0) reset(); let xIndex; let yind; // determine correct position if (pollind < options.numberOfCols) { xIndex = pollind; yind = 0; } else { xIndex = pollind - options.numberOfCols; yind = 1; } const polldata = [ 0, 0, 0, 0, 0 ]; let pollperc = [ 0, 0, 0, 0, 0 ]; let pollcounter = 0; // add them one by one const anim = setInterval(() => { animatepoll(1000); // eslint-disable-line no-use-before-define }, 1); // show poll results const animatepoll = pollsize => { if (pollcounter === pollsize) { clearInterval(anim); if (options.pollindex === 4) { options.setData({ continue: true }); } } pollcounter += 1; // draw random sample ('index' corresponds to class index in 'data.json') const index = bisect(options.data, Math.random() * 100); // add to polldata polldata[index] += 1; // calculate difference with result pollperc = polldata.map(score => (Math.round(score / pollcounter * 1000) / 10)); pollperc.forEach((element, i) => { pollperc[i] = Math.round((pollperc[i] - scores[i]) * 100) / 100; }); const distance = (options.width - options.xoffset * 2) / (options.numberOfCols - 1); const xBase = options.xoffset + xIndex * distance; // increase rectangle width svg.selectAll(`rect.diff${xIndex}${yind}`) .data(pollperc) .attr('width', d => (xScale(Math.abs(d)))) .attr('x', d => (d < 0 ? xBase - Math.abs(xScale(d)) : xBase)); // add text, format it svg.selectAll(`.difftext${xIndex}${yind}`) .data(pollperc) .attr('x', d => (d > 0 ? xBase + xScale(d) + 7 : xBase + xScale(d) - 6)) .attr('text-anchor', d => (d > 0 ? 'start' : 'end')) .text(d => repr(d)) .attr('fill-opacity', pollcounter > 100 ? 1 : 0); }; }; // start next poll generatepoll(options.pollindex); }; // "setter" poll.options = input => { Object.assign(options, input); return poll; }; return poll; };