PageSourceSearch

https://cfg.cz/js/cfg-v-cislech.js

js cfg.cz collected 2026-10-09 17:40:18 UTC 11,809 bytes, 271 lines download raw bytes

1/* CFG v číslech — jediný zdroj dat pro KPI, grafy a licence.
2   Hodnoty jsou v mil. Kč; přesné částky se z nich skládají do tooltipu. */
3(function () {
4  'use strict';
5
6  var DATA = {
7    /* Období, ke kterému platí KPI aktiv a portfolia. Poslední uzavřený rok,
8       ne průběžný stav — mezitímní hodnota je nižší a vedle rostoucí řady by
9       v profilu skupiny čtla jako propad. */
10    asOf: '31. 12. 2025',
11    foundedYear: 2012,
12    people: '50+',
13    licensedEntities: 3,
14    companiesAndProducts: 16,
15    turnoverStructureYear: '2025',
16    series: {
17      assets: {
18        title: 'Celková aktiva skupiny',
19        values: [
20          { label: '2022', value: 363.538 },
21          { label: '2023', value: 428.707 },
22          { label: '2024', value: 467.974 },
23          { label: '2025', value: 548.989 }
24        ]
25      },
26      property: {
27        title: 'Nemovitostní portfolio',
28        values: [
29          { label: '2022', value: 198.387 },
30          { label: '2023', value: 240.162 },
31          { label: '2024', value: 256.371 },
32          { label: '2025', value: 387.224 }
33        ]
34      },
35      turnover: {
36        title: 'Vývoj obratu',
37        values: [
38          { label: '2022', value: 81.384 },
39          { label: '2023', value: 69.808 },
40          { label: '2024', value: 97.914 },
41          { label: '2025', value: 126.620 }
42        ]
43      }
44    },
45    turnoverStructure: [
46      { label: 'Finanční služby', value: 14.885, share: 11.8 },
47      { label: 'Realitní činnosti', value: 79.254, share: 62.6 },
48      { label: 'Fintech', value: 32.481, share: 25.6 }
49    ]
50  };
51
52  window.CFG_NUMBERS_DATA = DATA;
53
54  /* Ikony na mřížce 32 v řeči .p-ico ze styles.css: tah kreslí [data-draw],
55     sloupce vyjíždějí přes [data-grow], tečka doskočí přes [data-pop].
56     Kaskádu uvnitř ikony drží inline --d, spouští ji [data-shown] na kartě. */
57  var ICONS = {
58    growth:
59      '<path d="M4.5 27H27.5" pathLength="1" data-draw="1" style="--d:0ms"/>' +
60      '<path d="M8.5 27V20.5" data-grow="1" style="--d:220ms"/>' +
61      '<path d="M14.5 27V16" data-grow="1" style="--d:310ms"/>' +
62      '<path d="M20.5 27V11" data-grow="1" style="--d:400ms"/>' +
63      '<path d="M23.6 6.5H28V10.9" pathLength="1" data-draw="1" style="--d:520ms"/>' +
64      '<path d="M27.6 6.9 21.2 13.3" pathLength="1" data-draw="1" style="--d:600ms"/>',
65    buildings:
66      '<path d="M5 27V13.5H13" pathLength="1" data-draw="1" style="--d:0ms"/>' +
67      '<path d="M13 27V6.5H24V27" pathLength="1" data-draw="1" style="--d:180ms"/>' +
68      '<path d="M3 27H29" pathLength="1" data-draw="1" style="--d:340ms"/>' +
69      '<path d="M16.8 11H20.2" pathLength="1" data-draw="1" style="--d:440ms"/>' +
70      '<path d="M16.8 16H20.2" pathLength="1" data-draw="1" style="--d:490ms"/>' +
71      '<path d="M16.8 21H20.2" pathLength="1" data-draw="1" style="--d:540ms"/>' +
72      '<path d="M8.2 18.5H10.2" pathLength="1" data-draw="1" style="--d:590ms"/>' +
73      '<path d="M8.2 22.5H10.2" pathLength="1" data-draw="1" style="--d:640ms"/>',
74    people:
75      '<circle cx="14.5" cy="10.6" r="4.6" pathLength="1" data-draw="1" style="--d:0ms"/>' +
76      '<path d="M6 26.6C6 21.1 9.8 18 14.5 18C19.2 18 23 21.1 23 26.6" pathLength="1" data-draw="1" style="--d:240ms"/>' +
77      '<path d="M26 7.4V12.6" pathLength="1" data-draw="1" style="--d:460ms"/>' +
78      '<path d="M23.4 10H28.6" pathLength="1" data-draw="1" style="--d:520ms"/>',
79    clock:
80      '<circle cx="16" cy="16" r="11" pathLength="1" data-draw="1" style="--d:0ms"/>' +
81      '<path d="M16 9.6V16.4L20.9 19.2" pathLength="1" data-draw="1" style="--d:320ms"/>' +
82      '<circle cx="16" cy="16" r="1.3" fill="currentColor" stroke="none" data-pop="1" style="--d:620ms"/>',
83    bank:
84      '<path d="M4 12 16 5.5 28 12" pathLength="1" data-draw="1" style="--d:0ms"/>' +
85      '<path d="M4.5 14.6H27.5" pathLength="1" data-draw="1" style="--d:200ms"/>' +
86      '<path d="M4 27H28" pathLength="1" data-draw="1" style="--d:280ms"/>' +
87      '<path d="M7 17.4V24.2" pathLength="1" data-draw="1" style="--d:400ms"/>' +
88      '<path d="M13 17.4V24.2" pathLength="1" data-draw="1" style="--d:450ms"/>' +
89      '<path d="M19 17.4V24.2" pathLength="1" data-draw="1" style="--d:500ms"/>' +
90      '<path d="M25 17.4V24.2" pathLength="1" data-draw="1" style="--d:550ms"/>',
91    grid:
92      '<path d="M5.5 5.5H14.5V14.5H5.5Z" pathLength="1" data-draw="1" style="--d:0ms"/>' +
93      '<path d="M17.5 5.5H26.5V14.5H17.5Z" pathLength="1" data-draw="1" style="--d:180ms"/>' +
94      '<path d="M5.5 17.5H14.5V26.5H5.5Z" pathLength="1" data-draw="1" style="--d:300ms"/>' +
95      '<path d="M17.5 17.5H26.5V26.5H17.5Z" pathLength="1" data-draw="1" style="--d:420ms"/>'
96  };
97
98  var oneDecimal = new Intl.NumberFormat('cs-CZ', {
99    minimumFractionDigits: 1,
100    maximumFractionDigits: 1
101  });
102  var wholeNumber = new Intl.NumberFormat('cs-CZ');
103
104  function latest(series) {
105    return series.values[series.values.length - 1];
106  }
107
108  function displayMillions(value) {
109    return oneDecimal.format(value);
110  }
111
112  function exactValue(value) {
113    return wholeNumber.format(Math.round(value * 1000)) + ' tis. Kč';
114  }
115
116  /* Roky na trhu k 1. 1. aktuálního roku, stejně jako data-years-since
117     na homepage — číslo se nemusí každý rok přepisovat. */
118  function yearsOnMarket() {
119    return Math.max(1, new Date().getFullYear() - DATA.foundedYear);
120  }
121
122  function icon(name) {
123    return '<span class="numbers-kpi__ico" aria-hidden="true">' +
124      '<svg class="p-ico" viewBox="0 0 32 32" fill="none" stroke="currentColor" ' +
125      'stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">' +
126      ICONS[name] + '</svg></span>';
127  }
128
129  function counter(value, decimals, duration, delay) {
130    return '<span data-count="' + value + '" data-count-decimals="' + (decimals || 0) + '"' +
131      (duration ? ' data-count-duration="' + duration + '"' : '') +
132      (delay ? ' data-count-delay="' + delay + '"' : '') + '>
132' +
133      (decimals ? oneDecimal.format(value) : wholeNumber.format(value)) +
134      '</span>';
135  }
136
137  function renderKpis() {
138    var target = document.querySelector('[data-numbers-kpis]');
139    if (!target) return;
140
141    var kpis = [
142      {
143        icon: 'growth',
144        value: latest(DATA.series.assets).value,
145        decimals: 1,
146        unit: 'mil. Kč',
147        label: 'Celková aktiva skupiny',
148        note: 'k ' + DATA.asOf
149      },
150      {
151        icon: 'buildings',
152        value: latest(DATA.series.property).value,
153        decimals: 1,
154        unit: 'mil. Kč',
155        label: 'Nemovitostní portfolio',
156        note: 'k ' + DATA.asOf
157      },
158      { icon: 'people', value: parseInt(DATA.people, 10), suffix: '+', label: 'Lidí napříč skupinou' },
159      { icon: 'clock', value: yearsOnMarket(), label: 'Let na trhu' },
160      {
161        icon: 'bank',
162        value: DATA.licensedEntities,
163        label: 'Licencované subjekty ČNB',
164        href: '/#licence'
165      },
166      {
167        icon: 'grid',
168        value: DATA.companiesAndProducts,
169        label: 'Klíčových společností a produktů',
170        href: '/projekty/'
171      }
172    ];
173
174    target.innerHTML = kpis.map(function (item) {
175      /* CTA je skutečný odkaz s textem, jen se přes ::after roztáhne přes
176         celou kartu — plocha je tak klikací celá, ale ve stromu zůstane
177         jeden cíl s vlastním popiskem. aria-label doplní cíl, protože
178         „Zobrazit více“ samo o sobě nic neříká. */
179      var cta = item.href
180        ? '<a class="numbers-kpi__cta" href="' + item.href + '" ' +
181            'aria-label="' + item.label + ' — zobrazit více">' +
182            'Zobrazit více <span aria-hidden="true">→</span>' +
183          '</a>'
184        : '';
185
186      return '<li class="numbers-kpi' + (item.href ? ' numbers-kpi--link' : '') + '" data-anim="1">' +
187        icon(item.icon) +
188        '<div class="numbers-kpi__body">' +
189          '<strong class="numbers-kpi__value">' + counter(item.value, item.decimals) +
190            (item.suffix ? '<span class="numbers-kpi__suffix">' + item.suffix + '</span>' : '') +
191            (item.unit ? '<span class="numbers-kpi__unit">' + item.unit + '</span>' : '') +
192          '</strong>' +
193          '<span class="numbers-kpi__label">' + item.label + '</span>' +
194          (item.note ? '<span class="numbers-kpi__note">' + item.note + '</span>' : '') +
195          cta +
196        '</div>' +
197        '</li>';
198    }).join('');
199  }
200
201  /* Strop stupnice je 18 % nad maximem řady, aby se popisek hodnoty vešel
202     nad nejvyšší sloupec a graf nekončil u stropu karty. Počet sloupců
203     nese --cols, takže grid nepotřebuje pravidlo na každou délku řady. */
204  function renderBarChart(series) {
205    var max = Math.max.apply(null, series.values.map(function (item) { return item.value; }));
206    var ceiling = max * 1.18;
207
208    return '<figure class="numbers-chart" data-anim="1">' +
209      '<figcaption class="numbers-chart__head">' +
210        '<h3>' + series.title + '</h3><span>mil. Kč</span>' +
211      '</figcaption>' +
212      '<div class="numbers-chart__plot" style="--cols:' + series.values.length + '">' +
213        series.values.map(function (item, index) {
214          var height = (item.value / ceiling * 100).toFixed(2);
215          var isLast = index === series.values.length - 1;
216          return '<div class="numbers-chart__col" title="' + item.label + ': ' + exactValue(item.value) + '">' +
217            '<div class="numbers-chart__track">' +
218              '<div class="numbers-chart__bar' + (isLast ? ' is-current' : '') + '" style="--bar-height:' + height + '%">' +
219                '<strong>' + counter(item.value, 1, 0, index * 75) + '</strong>' +
220              '</div>' +
221            '</div>' +
222            '<span class="numbers-chart__period">' + item.label + '</span>' +
223          '</div>';
224        }).join('') +
225      '</div>' +
226    '</figure>';
227  }
228
229  function renderDevelopment() {
230    var target = document.querySelector('[data-numbers-development]');
231    if (!target) return;
232    target.innerHTML =
233      renderBarChart(DATA.series.assets) +
234      renderBarChart(DATA.series.property);
235  }
236
237  function renderTurnover() {
238    var chartTarget = document.querySelector('[data-numbers-turnover]');
239    var structureTarget = document.querySelector('[data-numbers-structure]');
240    if (chartTarget) chartTarget.innerHTML = renderBarChart(DATA.series.turnover);
241    if (!structureTarget) return;
242
243    var total = DATA.turnoverStructure.reduce(function (sum, item) { return sum + item.value; }, 0);
244    structureTarget.innerHTML =
245      '<section class="numbers-structure" data-anim="1">' +
246        '<div class="numbers-structure__head">' +
247          '<h3>Struktura obratu ' + DATA.turnoverStructureYear + '</h3>' +
248          '<span>Celkem ' + counter(total, 1, 0, 120) + ' mil. Kč</span>' +
249        '</div>' +
250        '<div class="numbers-structure__stack" aria-hidden="true">' +
251          DATA.turnoverStructure.map(function (item, index) {
252            return '<span class="segment-' + (index + 1) + '" style="--share:' + item.share + '%"></span>';
253          }).join('') +
254        '</div>' +
255        '<div class="numbers-structure__items">' +
256          DATA.turnoverStructure.map(function (item, index) {
257            return '<div class="numbers-structure__item">' +
258              '<span class="numbers-structure__key segment-' + (index + 1) + '"></span>' +
259              '<div><strong>' + item.label + '</strong>' +
260              '<span>' + counter(item.value, 1, 0, 120 + index * 150) + ' mil. Kč · ' +
261                counter(item.share, 1, 0, 120 + index * 150) + ' %</span></div>' +
262            '</div>';
263          }).join('') +
264        '</div>' +
265      '</section>';
266  }
267
268  renderKpis();
269  renderDevelopment();
270  renderTurnover();
271})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.