import { col } from '../csv.js'; import { PALETTE, FONT, axisCommon, standalonePeriodAxis, titleStyle, standardLegend, financialViewLabel, lineSeries, footnote, watermarks, LAYOUT, } from '../theme.js'; /** * 泡泡玛特分地区零售门店数量与同比增速。 * 堆叠柱为各期末门店数,折线为全球合计数量的同比。 * 口径:2023年及以前"海外合计"含港澳台;2024年起港澳台单列并计入中国, * 海外合计 = 亚太 + 美洲 + 欧洲。两段口径不可直接跨 2023/2024 对比海外。 */ // 门店数是计数而非金额,保留整数(CLAUDE.md 一位小数规则针对金额/比率)。 const SEGMENT_COLORS = { mainland: '#3F7FBE', hkmtw: '#AECBE8', apac: '#36A28F', americas: '#E4A349', europe: PALETTE.brown, overseas: '#C2726B', }; // 段内标签文字色:浅色底(港澳台、美洲)用深字,深色底用白字 const INSIDE_LABEL_COLORS = { mainland: '#fff', hkmtw: PALETTE.ink, apac: '#fff', americas: PALETTE.ink, europe: '#fff', overseas: '#fff', }; const regions = [ { key: 'mainland', name: '中国内地' }, { key: 'hkmtw', name: '港澳台' }, { key: 'apac', name: '亚太' }, { key: 'americas', name: '美洲' }, { key: 'europe', name: '欧洲' }, { key: 'overseas', name: '海外合计(含港澳台)' }, ]; const num = (value) => (Number.isFinite(value) ? value : null); // 2024 起披露口径变为港澳台单列 + 亚太/美洲/欧洲分列;此前只有含港澳台的海外合计。 // 同一根柱内两种披露结构互斥出现,堆叠总和始终等于全球合计。 function stackValue(row, key) { const split = Number.isFinite(row.apac); if (key === 'overseas') return split ? null : num(row.overseas); if (!split && key !== 'mainland') return null; return num(row[key]); } export function storesRetailChart(rows, { width, height, view = 'all' }) { return { backgroundColor: '#fff', title: { ...titleStyle, text: `泡泡玛特分地区零售门店数量与同比增速(${financialViewLabel(view)})`, subtext: '柱状为各期末零售门店数(堆叠);折线为全球合计门店数量同比', }, legend: standardLegend([...regions.map((item) => item.name), '全球合计同比']), grid: { left: 78, right: 82, top: LAYOUT.gridTop, bottom: 100 }, tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' }, textStyle: { fontFamily: FONT }, }, xAxis: { ...standalonePeriodAxis, data: col(rows, 'period') }, yAxis: [ { ...axisCommon, type: 'value', name: '零售门店数量(家)', nameLocation: 'middle', nameGap: 52, nameTextStyle: { color: PALETTE.grey, fontSize: 13, fontFamily: FONT }, min: 0, max: 700, interval: 100, }, { ...axisCommon, type: 'value', name: '全球合计同比(%)', nameLocation: 'middle', nameGap: 60, nameRotate: -90, nameTextStyle: { color: PALETTE.grey, fontSize: 13, fontFamily: FONT }, min: 0, max: 100, interval: 20, axisLabel: { ...axisCommon.axisLabel, formatter: '{value}%' }, splitLine: { show: false }, }, ], series: [ ...regions.map((item) => ({ name: item.name, type: 'bar', stack: 'stores-retail', data: rows.map((row) => stackValue(row, item.key)), itemStyle: { color: SEGMENT_COLORS[item.key] }, // 每段标注门店数:浅色段用深字、深色段用白字,保证段内可读 label: { show: true, position: 'inside', fontSize: 10, fontWeight: 500, fontFamily: FONT, color: INSIDE_LABEL_COLORS[item.key], overflow: 'none', }, // 相邻矮段(如 2024H1 美洲/欧洲)标签贴得近时沿 y 向微移避让 labelLayout: { moveOverlap: 'shiftY' }, emphasis: { focus: 'series' }, })), { ...lineSeries({ name: '全球合计同比', data: col(rows, 'global_yoy'), color: '#8256B2', formatter: (p) => `${p.value.toFixed(1)}%`, }), yAxisIndex: 1, z: 10, }, ], graphic: [ ...watermarks(width, height), footnote('数据来源:泡泡玛特历年公告;门店数为各期末时点数\n2023年及以前海外合计含港澳台;2024年起港澳台单列,海外=亚太+美洲+欧洲 | @思考的Joey'), ], }; }