Source: view/viz/VoronoiRanking2D.js

/** @module */

import { castRankingFindPolygons } from '@paretoman/votekit-vote-casters'
import colorBlender, { rgbToString } from './colorBlender.js'

/**
 * Draw Voronoi cells to show votes.
 * @param {VoterGroup} voterGroup
 * @param {CandidateList} candidateList
 * @param {Screen} screen
 * @constructor
 */
export default function VoronoiRanking2D(voterGroup, candidateList, screen) {
    const self = this

    let canList
    let colors
    let cells
    self.update = function (votesForGeom) {
        // calculate colors

        let { rankings } = votesForGeom
        cells = votesForGeom.cells
        if (rankings === undefined || cells === undefined) {
            canList = candidateList.getEntities()
            const canPoints = canList.map((can) => [can.shape2.x, can.shape2.y])
            const voterGeom = voterGroup.shape2
            const verbosity = 3
            const cd = castRankingFindPolygons(voterGeom, canPoints, verbosity)
            rankings = cd.rankings
            cells = cd.cells
        }

        canList = candidateList.getEntities()

        const n = canList.length
        const cn = cells.length
        colors = Array(cn)
        const colorList = canList.map((can) => can.colorRGBA)
        for (let i = 0; i < cn; i++) {
            const bordaScores = rankings[i].map((r) => n - r)
            colors[i] = rgbToString(colorBlender(bordaScores, colorList))
        }
    }

    self.render = function () {
        const { ctx } = screen
        const { x, y, w } = voterGroup.shape2

        ctx.save()

        const cn = cells.length
        for (let i = 0; i < cn; i++) {
            ctx.beginPath()
            cellPath(ctx, cells[i])
            ctx.fillStyle = colors[i]
            ctx.strokeStyle = colors[i]
            ctx.fill()
            ctx.stroke()
        }

        // border
        ctx.strokeStyle = '#222'
        ctx.beginPath()
        ctx.arc(x, y, w * 0.5, 0, 2 * Math.PI)
        ctx.stroke()

        ctx.restore()
    }
}

function cellPath(ctx, cell) {
    const cc = cell.length
    const first = cell[cc - 1]
    ctx.moveTo(first[0], first[1])
    for (let i = 0; i < cc; i++) {
        const coord = cell[i]
        ctx.lineTo(coord[0], coord[1])
    }
}