/**
* Chart 4 — Сравнение регионов: две вертикальные панели рядом.
*
* Левая панель: зелёные бары (лидеры).
* Правая панель: оранжевые/светлые бары (аутсайдеры).
* Выбранный субъект: жёлтый/оранжевый highlight (isHighlight=true).
*
* Параметры:
* left: { title, bars: [{ label, value, isHighlight? }] }
* right: { title, bars: [{ label, value, isHighlight? }] }
* regionLabel: string
* unit: string
*/
const sharp = require('sharp')
const { PALETTE } = require('../data/palette')
const { dark: DARK, mdGray: MDGRAY, ltGray: LTGRAY, grid: GRID, green: GREEN, orange: ORANGE, o: YELLOW } = PALETTE
function esc (s) { return String(s).replace(/&/g,'&').replace(//g,'>') }
async function chart4_regionCompare ({ left, right, regionLabel, unit = 'руб./кг', width = 920 }) {
const W = width
const gap = 48
const panelW = (W - gap) / 2
const PL = 28, PR = 12, PT = 50, PB = 64
const cH = 260
// Общая шкала Y для честного сравнения
const allVals = [...left.bars.map(b => b.value), ...right.bars.map(b => b.value)]
const maxV = Math.max(...allVals) * 1.12
const minV = 0
const H = PT + cH + PB
const yV = v => PT + cH - (v - minV) / (maxV - minV) * cH
function renderPanel (bars, offsetX, title, defaultColor, isLeftPanel) {
const n = bars.length
const cW = panelW - PL - PR
const slotW = cW / n
const barW = Math.min(50, slotW * 0.68)
let s = ''
// Заголовок
s += `${esc(title)}`
// Y grid + labels (только у левой панели)
if (isLeftPanel) {
const step = maxV > 50 ? 10 : 5
for (let v = 0; v <= maxV; v += step) {
const y = yV(v)
s += ``
s += `${v}`
}
} else {
const step = maxV > 50 ? 10 : 5
for (let v = 0; v <= maxV; v += step) {
const y = yV(v)
s += ``
}
}
// Ось X внизу
s += ``
bars.forEach((b, i) => {
const cx = offsetX + PL + i * slotW + slotW / 2
const x = cx - barW / 2
const bH = Math.abs(yV(b.value) - yV(0))
const by = yV(b.value)
// Цвет: highlight → жёлтый, иначе — defaultColor
const color = b.isHighlight ? YELLOW : defaultColor
s += ``
// Значение над баром
s += `${b.value.toFixed(1)}`
// Подпись под осью (повёрнутая)
const labelX = cx, labelY = yV(0) + 12
const maxLen = Math.floor(slotW / 4.8)
const name = b.label.length > maxLen ? b.label.slice(0, maxLen) + '…' : b.label
s += `${esc(name)}`
})
// Подпись единиц
s += `${esc(unit)}`
return s
}
const leftSvg = renderPanel(left.bars, 0, left.title, GREEN, true)
const rightSvg = renderPanel(right.bars, panelW + gap, right.title, ORANGE, false)
// Разделительная линия между панелями
const divX = panelW + gap / 2
const dividerLine = ``
const fullSvg = ``
return {
buffer: await sharp(Buffer.from(fullSvg)).png({ quality: 95 }).toBuffer(),
width: W,
height: H + 40
}
}
module.exports = { chart4_regionCompare }