Source: view/viz/vizMESChartsCalcShape.js

/** @module */

/**
 * Calculate shape data for charts of budget for MES
 * @param {Object} sequenceResults - MES methodResults plus a little extra candidate data
 * @param {Object} screen
 * @param {Object} budgetDataMES
 * @returns chartDataMES
 */
export default function vizMESChartsCalcShape(phaseResults, screen, budgetDataMES) {
    const { socialChoiceResults, votes } = phaseResults
    const { winnersByRound } = socialChoiceResults.explanation

    const { costsByGeom, budgetsByGeom, colorRGBAByGeom } = budgetDataMES

    const { votesByGeom } = votes

    const nRounds = winnersByRound.length
    const nGeoms = votesByGeom.length

    const cols = 3
    const xScale = 1 / cols
    const yScale = -screen.width / cols
    const sizeChart = screen.width / cols

    const costShapesbyGeom = []
    const budgetShapesbyGeom = []

    for (let g = 0; g < nGeoms; g++) {
        const { grid, voteIndex, voterGeom } = votesByGeom[g]
        const { w, densityProfile } = voterGeom
        const xCenter = voterGeom.x

        const gridX = grid.x
        const isGauss = (densityProfile === 'gaussian')
        const sigma = w / Math.sqrt(2 * Math.PI) // w = sigma * sqrt(2*pi)

        const nVotes = voteIndex.length

        const budgets = budgetsByGeom[g]
        const costs = costsByGeom[g]

        const budgetShapes = []
        const costShapes = []

        for (let r = 0; r < nRounds; r++) {
            const curBudget = budgets[r]
            const curCost = costs[r]
            const budgetShape = []
            const costShape = []

            // Place graph in row and column
            const idCol = r % cols
            const idRow = Math.floor(r / cols)
            const xTranslate = idCol * sizeChart
            const yTranslate = (idRow + 1) * sizeChart

            let p = 0 // point counter

            // start bottom left
            // go outside of screen by one pixel
            const bottom = 0 * yScale + yTranslate
            const left = Math.max(-1, gridX[0]) * xScale + xTranslate
            budgetShape[p] = [left, bottom]
            costShape[p] = [left, bottom]
            p += 1

            for (let i = 0; i < nVotes; i++) {
                const xg = gridX[i]
                if (xg < -1) continue
                if (xg > screen.width + 1) continue
                const shapeMult = (isGauss) ? Math.exp(-0.5 * ((xg - xCenter) / sigma) ** 2) : 1

                // The shape is affected by the density of voters.
                const dCurCosti = curCost[i] * shapeMult
                const dCurBudgeti = curBudget[i] * shapeMult

                // add point
                const xb = xg * xScale + xTranslate
                const yb = dCurBudgeti * yScale + yTranslate
                budgetShape[p] = [xb, yb]
                const xc = xg * xScale + xTranslate
                const yc = dCurCosti * yScale + yTranslate
                costShape[p] = [xc, yc]
                p += 1
            }

            // end bottom right
            const right = Math.min(screen.width + 1, gridX[nVotes - 1]) * xScale + xTranslate
            budgetShape[p] = [right, bottom]
            costShape[p] = [right, bottom]
            p += 1

            // close path
            budgetShape[p] = [left, bottom]
            costShape[p] = [left, bottom]
            p += 1

            costShapes[r] = costShape
            budgetShapes[r] = budgetShape
        }
        costShapesbyGeom[g] = costShapes
        budgetShapesbyGeom[g] = budgetShapes
    }

    const chartDataMES = { costShapesbyGeom, budgetShapesbyGeom, colorRGBAByGeom }
    return chartDataMES
}