Skip to content

Industrial production up by 0.2% in the euro area and by 0.1% in the EU

[]
0) { let rootNavigationList = fragmentElement.querySelector(‘.ecl-inpage-navigation__list’); let sampleSubNavigationList = fragmentElement.querySelector(‘#sample-sub-inpage-navigation-list’); sampleSubNavigationList.classList.add(‘hide’); let sampleNavigationItem = fragmentElement.querySelector(‘.ecl-inpage-navigation__item’); sampleNavigationItem.classList.add(‘hide’); let skipButtonHref = ”; let currentLevel = 0; let currentNavigationList = rootNavigationList; let lastNavigationItem = null; let newNavigationItem = null; for (let i = 0; i { element.classList.remove(‘has-active-item’); }); } function updateCompactedItems(event) { const activeNavItem = document.querySelector(‘.ecl-inpage-navigation__item–active’); if (activeNavItem !== null) { let parentNavItem = activeNavItem; if (activeNavItem.parentElement.classList.contains(‘estat-inpage-navigation–compact’)) { parentNavItem = activeNavItem.parentElement.parentElement; } if (!parentNavItem.classList.contains(‘has-active-item’)) { clearActivatedParents(); parentNavItem.classList.add(‘has-active-item’); } } else { clearActivatedParents(); } } function navItemObserverCallback(mutationList, observer) { mutationList.forEach(function(mutation) { if (mutation.type === ‘attributes’ && mutation.attributeName === ‘class’) { updateCompactedItems(); } }); } function navItemObserverInit() { const options = {attributes: true}; const navItemObserver = new MutationObserver(navItemObserverCallback); const navItems = document.querySelectorAll(‘.ecl-inpage-navigation__item’); navItems.forEach((navItem) => { navItemObserver.observe(navItem, options); }); } $(document).ready(function() { const notInEditMode = document.querySelector(‘.fragments-editor’) == null; if (notInEditMode) { inpageNavigationFragmentInit(); const isHasSelectorSupported = CSS.supports(‘selector(:has(*))’); if (!isHasSelectorSupported && document.querySelector(‘nav.in-compact-mode’) !== null) { console.log(‘has() selector is not supported -> navigation in compact mode is handled by auxiliary scripts’); navItemObserverInit(); }; ECL.autoInit(); } else { const sampleNavigationItem = fragmentElement.querySelector(‘.ecl-inpage-navigation__item’); sampleNavigationItem.classList.remove(‘hide’); }; });;}());]]>

Printing can have negative environmental impacts due to paper waste. We encourage you to explore eco-friendly alternatives. Bookmarking this page in your browser allows you to access it anytime.

This publication can also be converted to PDF, if you have a PDF printer installed on your computer. PDF printers function as virtual printers, enabling you to create digital copies of web pages and access the content offline.

{ const buttonPrintPage = document.getElementById(‘estat-print-page-modal-toggle’); const cookieSkipModal = ‘skipModalBeforePrinting’; if (configuration.displayInPageHeader) { const headerElement = document.querySelector(‘.ecl-page-header .ecl-page-header__meta’) || document.querySelector(‘.ecl-page-header .ecl-page-header__title-container ‘) if (headerElement) { headerElement.prepend(buttonPrintPage); headerElement.classList.add(‘ecl-u-width-100’) } } buttonPrintPage.addEventListener(‘click’, () => { const skipModal = readCookie(cookieSkipModal); if (skipModal == ‘true’) { window.print(); } else { const eclModalElement = document.getElementById(‘estat-print-page-modal’); const eclModal = ECL.components.get(eclModalElement); eclModal.openModal(); } }); document.getElementById(‘print-submit’).addEventListener(‘click’, () => { const skipModal = document.getElementById(‘checkbox-skip-modal’).checked if (skipModal) { writeCookieWithMaxAgeValue(cookieSkipModal, ‘true’, 15768000); } else { deleteCookie(cookieSkipModal); } window.print(); }); });;}());]]>

Down by 1.9% in the euro area and by 1.7% in the EU compared with November 2023

Overview

In November 2024, compared with October 2024, seasonally adjusted industrial production increased by 0.2% in the euro area and by 0.1% the EU, according to first estimates from Eurostat, the statistical office of the European Union. In October 2024, industrial production grew by 0.2% in the euro area and by 0.4% in the EU.

In November 2024, compared with November 2023, industrial production decreased by 1.9% the euro area and by 1.7% in the EU.

Industrial production

Monthly comparison by main industrial grouping and by Member State

In the euro area in November 2024, compared with October 2024, industrial production

  • increased by 0.5% for intermediate goods,

  • increased by 1.1% for energy,

  • increased by 0.5% for capital goods,

  • increased by 1.5% for durable consumer goods,

  • increased by 0.1% for non-durable consumer goods.

In the EU, industrial production

  • increased by 0.4% for intermediate goods,

  • increased by 1.3% for energy,

  • increased by 0.1% for capital goods,

  • increased by 1.1% for durable consumer goods,

  • decreased by 0.1% for non-durable consumer goods.

The highest monthly increases were recorded in Belgium (+8.7%), Malta (+7.1%) and Lithuania (+4.3%). The largest decreases were observed in Ireland (-5.8%), Luxembourg (-3.9%) and Portugal (-3.4%).

Annual comparison by main industrial grouping and by Member State

In the euro area in November 2024, compared with November 2023, industrial production

  • decreased by 2.5% for intermediate goods,

  • decreased by 1.3% for energy,

  • decreased by 2.8% for capital goods,

  • decreased by 1.0% for durable consumer goods,

  • remained stable for non-durable consumer goods.

In the EU, industrial production

  • decreased by 1.9% for intermediate goods,

  • decreased by 0.8% for energy,

  • decreased by 2.6% for capital goods,

  • remained stable for durable consumer goods,

  • increased by 0.1% for non-durable consumer goods.

The largest annual decreases were recorded in Croatia (-6.6%), Ireland (-5.6%) and Austria (-5.0%). The highest increases were observed in Malta (+13.5%), Belgium (+8.7%) and Greece (+4.8%).

Industrial production in November 2024

Tables

Industrial production

% change compared with previous month*

2024

Jun

Jul

Aug

Sep

Oct

Nov

0.5

-0.4

1.2

-1.6

0.2

0.2

0.2

-0.4

0.1

-1.5

0.3

0.5

1.7

0.1

0.2

-1.0

-1.3

1.1

0.4

-1.2

2.9

-3.7

1.7

0.5

3.9

-3.2

1.8

-0.4

-1.6

1.5

-2.0

2.0

-0.3

2.2

-2.4

0.1

 

 

 

 

 

 

0.6

-0.3

1.0

-1.5

0.4

0.1

0.4

-0.7

0.2

-1.2

0.5

0.4

1.3

0.0

0.3

-1.3

-0.8

1.3

0.5

-1.3

2.9

-3.1

1.6

0.1

3.3

-2.6

1.4

-0.5

-0.5

1.1

-1.4

2.6

-1.0

1.0

-1.3

-0.1

Industrial production

% change compared with previous month*

2024

Jun

Jul

Aug

Sep

Oct

Nov

0.5

-0.4

1.2

-1.6

0.2

0.2

0.6

-0.3

1.0

-1.5

0.4

0.1

-6.8

6.4

0.0

0.3

-4.9

8.7

0.1

0.6

0.9

1.3

-0.9

0.0

0.9

-0.8

1.8

-0.5

-0.6

-1.6

0.6

7.9

-5.4

-5.1

5.5

-3.3

2.0

-3.2

3.2

-2.5

-0.4

1.3

-3.5

-4.7

1.7

1.0

1.4

2.8

-1.6

6.8

0.4

-6.3

5.0

-5.8

1.7

2.0

-4.3

-2.7

0.8

2.7

0.4

-0.6

-0.4

1.0

0.9

-1.5

0.9

0.2

1.0

-0.8

-0.3

0.2

-2.4

6.2

-4.6

5.8

-3.9

-2.4

0.5

-0.9

0.0

-0.3

0.1

0.3

1.4

-1.8

-0.6

0.2

0.9

-2.6

-2.3

1.2

1.3

-1.3

0.5

-0.3

-1.9

1.3

3.0

0.3

-6.5

4.3

-1.7

0.3

-6.1

6.1

0.4

-3.9

0.6

0.0

-0.4

-0.7

2.0

-1.6

1.0

-4.4

2.0

4.2

-1.0

7.1

0.4

-0.9

1.8

-2.4

0.4

1.5

0.9

0.5

-0.5

-1.0

-1.4

-0.4

1.2

-0.4

-0.8

-0.5

3.5

-1.4

-3.7

-0.4

-0.3

3.0

3.4

-3.4

3.8

-3.2

1.3

0.0

0.4

-0.6

4.2

-2.8

-0.1

1.7

2.5

-1.4

2.1

-2.9

1.5

1.3

0.8

-1.3

3.8

1.6

-0.9

-1.5

0.4

1.4

-1.2

0.9

1.5

0.9

-1.3

1.7

7.2

-5.0

-1.6

-11.2

9.8

0.1

-0.6

4.0

-6.3

0.5

:

:

Industrial production

% change compared with same month of the previous year*

2024

Jun

Jul

Aug

Sep

Oct

Nov

-3.9

-2.2

-0.4

-2.1

-1.1

-1.9

-5.7

-4.4

-2.7

-4.2

-3.3

-2.5

1.7

0.9

2.2

2.1

-0.5

-1.3

-6.6

-3.6

-0.4

-5.8

-1.8

-2.8

-2.6

-4.8

-5.4

-3.1

-4.2

-1.0

1.0

2.4

1.7

5.6

3.7

0.0

 

 

 

 

 

 

-3.3

-1.6

-0.1

-1.7

-0.6

-1.7

-4.8

-4.1

-2.4

-3.6

-2.9

-1.9

2.2

1.1

2.2

1.5

-1.0

-0.8

-6.2

-4.0

-0.4

-5.1

-1.7

-2.6

-2.2

-4.2

-4.5

-2.7

-2.6

0.0

1.6

4.3

2.9

5.1

4.0

0.1

Industrial production

% change compared with same month of the previous year*

2024

Jun

Jul

Aug

Sep

Oct

Nov

-3.9

-2.2

-0.4

-2.1

-1.1

-1.9

-3.3

-1.6

-0.1

-1.7

-0.6

-1.7

-5.4

0.1

4.2

5.5

-6.0

8.7

-4.9

-2.6

-3.0

1.2

-1.5

2.8

-3.3

-2.1

1.7

1.7

-2.1

-2.7

3.2

20.9

12.9

6.2

9.0

-1.0

-4.0

-5.9

-2.8

-4.3

-4.5

-3.3

-3.2

-5.8

-6.0

-1.6

0.0

-0.1

-16.7

7.3

11.2

-0.6

15.1

-5.6

9.8

10.5

3.8

2.5

-2.7

4.8

0.4

-0.9

-1.5

0.7

3.1

-0.8

-1.3

-1.2

0.8

-0.8

-1.0

-1.1

-8.2

1.6

-2.1

1.0

-2.0

-6.6

-2.6

-3.3

-3.2

-3.9

-3.5

-1.5

6.8

2.3

1.4

0.4

2.8

-3.0

-5.5

1.7

0.6

-2.0

-1.9

-3.0

0.6

5.4

5.0

4.6

0.3

4.1

-1.9

-1.5

-10.0

0.4

-0.7

-3.9

-3.7

-6.6

-4.2

-5.4

-3.1

-2.9

7.3

-0.4

2.1

5.7

6.2

13.5

-3.5

-3.1

0.8

-1.9

-0.4

1.5

-3.6

-2.0

-2.8

-3.5

-4.6

-5.0

1.1

1.3

-0.5

-1.3

3.0

0.9

-2.9

-3.0

-1.9

2.5

3.9

-2.2

0.4

-4.0

-2.0

-3.8

-1.0

-1.5

-1.2

-1.6

6.1

-0.3

3.6

-0.7

-4.2

5.4

1.0

2.5

1.3

0.1

2.9

5.9

2.6

0.5

0.7

3.1

1.4

-2.4

-1.0

1.9

-1.8

0.8

14.9

10.0

5.9

-0.5

2.1

0.4

6.0

10.8

-0.4

-0.8

:

:

Production indices for total industry, calendar and seasonally adjusted

(base year 2021)

2024

Jun

Jul

Aug

Sep

Oct

Nov

97.0

96.6

97.8

96.2

96.4

96.6

98.6

98.3

99.3

97.8

98.2

98.3

86.5

92.0

92.0

92.3

87.8

95.4

99.2

99.8

100.7

102.0

101.1

101.1

99.2

98.4

100.2

99.7

99.1

97.5

131.4

141.8

134.2

127.4

134.4

129.9

93.6

90.6

93.5

91.2

90.8

92.0

85.6

81.6

83.0

83.8

85.0

87.4

101.3

108.2

108.6

101.8

106.9

100.7

112.7

115.0

110.0

107.0

107.9

110.8

101.0

100.5

100.1

101.1

102.0

100.5

100.0

100.2

101.2

100.4

100.1

100.3

96.0

102.0

97.3

102.9

98.9

96.5

95.4

94.5

94.5

94.2

94.3

94.6

109.1

107.1

106.5

106.7

107.7

104.9

92.6

93.7

94.9

93.7

94.2

93.9

104.1

105.5

108.7

109.0

101.9

106.3

90.1

90.4

84.9

90.0

90.5

87.0

96.5

96.5

96.1

95.4

97.3

95.7

113.0

108.0

110.2

114.8

113.7

121.8

101.2

100.3

102.1

99.6

100.0

101.5

101.5

102.0

101.5

100.5

99.1

98.7

110.7

110.3

109.4

108.9

112.7

111.1

94.7

94.3

94.0

96.8

100.1

96.7

98.4

95.3

96.5

96.5

96.9

96.3

96.1

93.4

93.3

94.9

97.3

95.9

100.0

97.1

98.6

99.9

100.7

99.4

102.3

103.9

103.0

101.5

101.9

103.3

99.3

100.2

101.7

102.6

101.3

103.0

113.0

107.4

105.7

93.9

103.1

103.2

111.2

115.6

108.3

108.8

:

:

Production indices for total industry, calendar adjusted

(base year 2021)

2024

Jun

Jul

Aug

Sep

Oct

Nov

99.1

97.9

83.0

101.4

101.9

103.2

100.7

98.0

85.4

102.6

103.9

104.6

90.7

86.2

84.0

97.0

93.5

97.0

101.3

103.1

98.6

102.7

106.0

105.3

104.2

88.0

93.6

103.3

105.2

105.7

133.0

129.8

131.0

130.1

136.4

132.3

95.2

90.4

86.0

95.4

93.3

98.4

85.9

72.5

81.1

86.2

90.6

91.0

92.6

111.7

94.0

124.3

124.6

125.6

117.5

128.4

104.2

109.0

106.4

107.9

105.9

104.9

77.7

104.3

108.3

105.2

104.0

98.6

79.7

101.6

105.1

104.2

98.0

109.0

84.6

106.2

106.5

100.1

99.7

103.8

64.0

99.7

102.5

99.0

116.9

121.5

89.6

112.9

110.8

103.4

96.3

93.7

99.6

96.0

101.1

102.7

104.2

101.8

108.4

111.7

107.3

109.9

92.2

89.2

71.3

91.9

95.9

89.1

100.2

95.2

84.7

103.2

102.7

100.8

117.9

113.8

104.1

120.4

119.0

124.5

104.4

98.5

93.3

100.8

103.0

104.9

105.2

101.9

90.4

105.0

103.2

104.1

111.7

105.5

102.2

111.4

120.0

115.5

94.9

100.7

79.4

98.3

101.6

100.7

100.5

96.4

88.0

98.7

101.9

101.0

100.9

93.5

78.2

98.1

102.7

100.6

101.0

88.5

90.7

100.3

109.8

105.9

103.9

91.4

100.5

104.4

106.3

107.1

103.0

78.3

86.8

105.7

108.2

109.5

102.4

106.4

105.9

81.9

106.5

107.5

118.3

113.0

99.5

108.6

:

:

Notes for users

Revisions and timetable

Compared with data issued in the News Release of 13 December 2024, the monthly percentage change for October 2024 has been revised from 0.0% to +0.2% in the euro area and from +0.3% to +0.4% in the EU. The annual percentage change has been revised from -1.2% to -1.1% in the euro area and from -0.8% to -0.6% in the EU.

Methods and definitions

The index of industrial production measures the evolution of the volume of production for industry excluding construction, based on data adjusted for calendar and seasonal effects.

Seasonally adjusted euro area and EU series are calculated by aggregating the seasonally adjusted national data.

Total industry covers NACE rev.2 sections B to D. Missing observations from Member States for recent months are estimated for the calculation of the euro area and the EU aggregates.

Starting with reference period January 2024, the base year of the data has been changed to 2021, since 2018 the base year had been 2015. More information on the reasons for and impact of the base year change can be found in the related Statistics Explained article.

Geographical information

The euro area (EA20) includes Belgium, Germany, Estonia, Ireland, Greece, Spain, France, Croatia, Italy, Cyprus, Latvia, Lithuania, Luxembourg, Malta, the Netherlands, Austria, Portugal, Slovenia, Slovakia and Finland.

The European Union (EU27) includes Belgium, Bulgaria, Czechia, Denmark, Germany, Estonia, Ireland, Greece, Spain, France, Croatia, Italy, Cyprus, Latvia, Lithuania, Luxembourg, Hungary, Malta, the Netherlands, Austria, Poland, Portugal, Romania, Slovenia, Slovakia, Finland and Sweden.

For more information

Share the release

Share component will be rendered here.

{ /** We adapt the structure of the tables */ tableConfiguration(); /** We configure the tables in order to make them sortable */ setDynamicTables(); // }, 3000); /** We configure the charts, converting the images to dynamic charts */ setTimeout(() => { setDynamicCharts(); }, 0); } /** * Opens the Printer options in order to print the html document */ function printDocument() { window.print(); } /** * Configures the tables according to the expected structure given by Regine * *

* Here the title *

… *

… * * Here the logo and notes * * @todo: this function will be called before sending the document to Liferay * @todo: 21/12/2022 – After discussing with Csaba, Liferay will try to adapt the structure in their * Java process before storing the document. */ function tableConfiguration() { /** Retrieves the list of table elements (images) */ var tables = document.getElementsByTagName(‘table’); /** We go through the list of tables */ for (var i = 0; i < tables.length; i++) { /** We create a section to wrap the table */ var section = document.createElement('section'); /** Add table-wrapper class to section element */ section.classList.add('table-wrapper'); /** We create a caption element to place the title */ var caption = document.createElement('caption'); /** We create thead element to place the headers */ var tHead = document.createElement('thead'); /** We create a footer to place notes, datasource and logo */ var footer = document.createElement('footer'); /** Retrieves the table */ var table = tables[i]; /** Retrieves the tBody */ var tBody = table.tBodies[0]; /** Retrieves the table rows */ var rows = tBody.rows; var datalabels = []; var captionContent = []; /** Stores the indexes of the rows to be removed after processing the whole table */ var rowsToRemove = []; /** We go through the rows within the table and extract caption, headers and footnotes */ buildTable(rows, captionContent, datalabels, footer, rowsToRemove); deleteRows(table, rowsToRemove); addTableCaption(caption, captionContent); addTableHeaders(table, tHead, datalabels); wrapInSection(section, table, caption, tHead, tBody, footer); linkHeaders(table); } } /** * Builds a table with the expected format: adding caption, datalabels and footer * @param {*} rows - The table rows * @param {*} captionContent - The content of the caption (title) * @param {*} datalabels - The list of datalabels (table headers) * @param {*} footer - The footer element * @param {*} rowsToRemove - Array containing the index of the rows to be removed */ function buildTable(rows, captionContent, datalabels, footer, rowsToRemove) { for (var rowIndex = 0; rowIndex -1; } /** * Whether a cell is a caption (title) * @param {*} cell - The cell to be checked * @returns true if the cell is a caption, false otherwise */ function isCaption(cell) { return checkCell(cell, 'th', 'title'); } /** * Whether a cell is a datalabel * @param {*} cell - The cell to be checked * @returns true if the cell is a datalabel, false otherwise */ function isDatalabel(cell) { return checkCell(cell, 'th', 'datalabel'); } /** * Whether a cell is a vertical header * @param {*} cell - The cell to be checked * @returns true if the cell is a vertical header, false otherwise */ function isVerticalHeader(cell) { return checkCell(cell, 'th', 'vertical-header'); } /** * Whether a cell is a footer * @param {*} cell - The cell to be checked * @returns true if the cell is a footer, false otherwise */ function isFooter(cell) { return checkCell(cell, 'td', 'footer'); } /** * Adds the content of the caption cells: paragraphs * @param {*} cells - The cells belonging to the row * @param {*} captionContent - The content of the caption * @param {*} rowIndex - The index of current row * @param {*} rowsToRemove - Array containing the index of the rows to be removed */ function addCaption(cells, captionContent, rowIndex, rowsToRemove) { for (var k = 0; k < cells.length; k++) { /** We retrive each cell */ var cell = cells[k]; /** We must add all the Child Nodes of each th title Cell */ for (var l = 0; l = 0; j--) { table.deleteRow(rowsToRemove[j]); } } /** * Adds the caption to the table. * @param {*} caption - The caption dom element * @param {*} captionContent - The content of the caption */ function addTableCaption(caption, captionContent) { /** We go through the Caption Content and append the nodes to the caption element */ for (var j = 0; j < captionContent.length; j++) { caption.appendChild(captionContent[j]); } } /** * Adds the headers to the table * @param {*} table - The table to make sortable * @param {*} tHead - The thead dom element * @param {*} datalabels - The datalabels to be added (headers) */ function addTableHeaders(table, tHead, datalabels) { var sortable = false; /** We go through the header rows and append them to the tHead element */ for (var i = 0; i < datalabels.length; i++) { var datalabelRow = datalabels[i]; var cells = datalabelRow.cells; for (var j = 0; j < cells.length; j++) { var th = cells[j]; if (th.classList.contains('sortable')) { sortable = true; var button = createNewSortButton(); th.appendChild(button); } } tHead.appendChild(datalabelRow); } if (sortable) { table.classList.add('sortable'); } } function createNewSortButton() { // creates sort button const button = document.createElement('button'); button.classList.add('ecl-table__arrow'); // creates a generic svg element for the two arrows const svgIconUp = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svgIconUp.setAttribute('xml:space', 'preserve'); svgIconUp.setAttribute('viewBox', '0 0 24 24'); svgIconUp.setAttribute('enable-background', 'new 0 0 24 24'); svgIconUp.setAttribute('focusable', 'false'); svgIconUp.setAttribute('aria-hidden', 'true'); svgIconUp.setAttribute('class', 'ecl-table__icon ecl-icon ecl-icon--m'); // adds path element of the arrow to the arrow svg const pathIconArrow = document.createElementNS('http://www.w3.org/2000/svg', 'path'); pathIconArrow.setAttribute('d', 'M7.4 13 11 9.4c.5-.5 1.4-.5 2 0l3.6 3.6c.9.9.2 2.4-1 2.4H8.4c-1.3 0-1.9-1.5-1-2.4'); svgIconUp.appendChild(pathIconArrow); // clones the generic arrow svg including the child path also const svgIconDown = svgIconUp.cloneNode(true); // seups the arrow directions to up and down by extra css classes svgIconUp.classList.add('ecl-table__icon-up'); svgIconDown.classList.add('ecl-table__icon-down'); // insert the two arrow svg elements into the button button.appendChild(svgIconUp); button.appendChild(svgIconDown); return button; } /** * Places all the elements in their places and wraps the table into a section. * @param {*} section - The section (dom element) which will wrap table and footer * @param {*} table - The table to be wrapped * @param {*} caption - The caption (dom element) to be added to the table * @param {*} tHead - The thead (dom element) to be added to the table * @param {*} tBody - The tbody (dom element) to be added to the table * @param {*} footer - The footer (dom element) to be added to the section */ function wrapInSection(section, table, caption, tHead, tBody, footer) { /** We insert caption and thead before tbody */ table.insertBefore(caption, tBody); table.insertBefore(tHead, tBody); /** We wrap the table into a section */ table.parentNode.insertBefore(section, table); section.appendChild(table); section.appendChild(footer); } /** * Adds ids and header attributes to link every cell to all related headers so that machines can correctly read the figures. * @param {*} table - The table to be wrapped * @todo: to be implemented */ function linkHeaders(table) { var tHead = table.tHead; var tBody = table.tBodies ? table.tBodies[0] : null; var headers = []; if (tHead) { var rows = tHead.rows; for (var i = 0; i < rows.length; i++) { var row = rows[i]; /** We add a new row in the headers array */ headers.push([]); var cells = row.cells; /** Stores the header ids and colSpan so we can guess to which cells (td) we must add the headers */ for (var j = 0; j < cells.length; j++) { var cell = cells[j]; cell.setAttribute('id', 'h_' + i + '_' + j); headers[i].push({ id: cell.id, colSpan: cell.colSpan ? cell.colSpan : 1 }); } } } if (tBody) { var rows = tBody.rows; for (var i = 0; i < rows.length; i++) { var row = rows[i]; var cells = row.cells; for (var j = 0; j -1) { cell.setAttribute('id', 'vh_' + i + '_' + j); /** * @todo: moe, we must identify the colgroup * If the colSpan is the same as the total we asume the scope is colgroup */ // if () { // cell.setAttribute('scope', 'colgroup'); // } } var headerLinks = getHeaderLinks(headers, j, cell.colSpan, cells[0]); cell.setAttribute('headers', headerLinks); } } } } /** * Retrieves the header (ths) ids in order to link them to a specific cell (td) * @param {*} rows - The rows containing all headers * @param {*} index - The index of the specific cell * @param {*} colSpan - The colspan of the specific cell * @param {*} firstCell - The first cell of the row. Used to reference possible vertical headers * @todo: take into account the colspan of the given cell * @returns A string containing the list of header ids split by spaces */ function getHeaderLinks(rows, index, colSpan, firstCell) { /** It will contain the header ids */ var links = ''; /** We add the reference of the vertical header if there is */ if (index > 0 && firstCell.className.indexOf(‘vertical-header’) > -1) { links = firstCell.id; } /** If colspan is not defined, we set it as 1 by default */ colSpan = colSpan ? colSpan : 1; /** We go through the list of header rows */ for (var i = 0; i < rows.length; i++) { var headers = rows[i]; /** Accumulates the colspan of the checked headers */ var sumColSpan = 0; /** We go through the list of headers for the specific header row */ for (var j = 0; j = sumColSpan && index < header.colSpan + sumColSpan) { links += links === '' ? header.id : ' ' + header.id; } sumColSpan += header.colSpan; } } return links; } /** * Sets the tables dynamic (sortable) */ function setDynamicTables() { var sortableTables = document.querySelectorAll('table'); for (var i = 0; i < sortableTables.length; i++) { new SortableTable(sortableTables[i]); } } /** * Chart Configuration in order to make the charts dynamic */ function setDynamicCharts() { /** Retrieves the list of charts elements (images) */ var charts = document.getElementsByClassName('chart'); /** We go through the list of charts */ for (var i = 0; i chartObj.resize()).observe(chartDiv); /** @todo: to be implemented */ // const btn = document.createElement("button"); // btn.innerHTML = "Chart Button"; // chartDiv.parentNode.insertBefore(btn, chartDiv); } } /** * Customizes the chart by applying custom events, axis formats, tooltips, and axis labels. * @param option - The chart options object. */ function customChartOptions(option) { setClickableDatasourceLinks(option); setAxisFormatter(option); setTooltipFormatter(option); } /** * Attaches event handlers to a chart: 'legendselectchanged'. * * @param {Chart} chart - The chart object. */ function addEventHandlers(chart) { /** Attach an event handler for the 'legendselectchanged' event */ chart.on('legendselectchanged', (event) => { /** Call the onChartLegendSelected function with the event and chart object */ onChartLegendSelected(event, chart); }); } /** * Handles the legend selected changed event of the chart. * @param {any} event – The event object containing the selected legend items. * @param {any} chart – The chart object. * @todo: Notify Liferay’s team about these chart events */ function onChartLegendSelected(event, chart) { /** Get the selected legend items */ const selected = event.selected; /** Count the number of selected legend items */ const selectedCount = Object.values(selected).filter(Boolean).length; /** If all legend items are deselected, keep the selection on the last clicked item */ if (selectedCount === 0) { selected[event.name] = true; } /** Update the legend selection */ chart.setOption({ legend: { selected: selected } }); } /** * Attaches custom events to the provided option object. * * @param {object} option – The option object to attach custom events to. */ function setClickableDatasourceLinks(option) { /** If the table has datasource link */ if (option.graphic && option.graphic.length >= 3) { /** Attach an onclick event handler to the third element of the graphic array (datasource links) */ option.graphic[2].onclick = function (event) { /** If the element has a link defined in its style */ if (this.style && this.style.link) { /** Open the link in a new tab/window */ window.open(this.style.link, ‘_blank’); } }; } } /** * Sets the default axis formatter for axis labels. * @param {object} option – The option object to update the axis formatter * */ function setAxisFormatter(option) { /** The default unit used in axis labels */ var defaultUnit = ‘%’; /** If the yAxis are used as values */ if (option.yAxis.type === ‘value’) { /** If the yAxis unit is not defined, set % as default */ option.yAxis.axisLabel.unit = option.yAxis.axisLabel.unit ? option.yAxis.axisLabel.unit : defaultUnit; /** If the yAxis label padding is not defined, set 15 as default suffix */ option.yAxis.axisLabel.padding = option.yAxis?.axisLabel?.padding ? option.yAxis.axisLabel.padding : 15; /** Use the custom formatter */ option.yAxis.axisLabel.formatter = (value) => customAxisFormatter(option.lang, value, option.yAxis.axisLabel.unit, parseInt(option.yAxis.axisLabel.decimals)); // Use the custom formatter } /** If the xAxis are used as values */ if (option.xAxis.type === ‘value’) { /** If the xAxis unit is not defined, set % as default */ option.xAxis.axisLabel.unit = option.xAxis.axisLabel.unit ? option.xAxis.axisLabel.unit : defaultUnit; /** Use the custom formatter */ option.xAxis.axisLabel.formatter = (value) => customAxisFormatter(option.lang, value, option.xAxis.axisLabel.unit, parseInt(option.xAxis.axisLabel.decimals)); } /** If xAxis type is category */ else if (option.xAxis.type === ‘category’) { boldCountries(option); } } /** * Formats a numeric value with a specified unit and decimal precision. * * @param {number} value – The numeric value to be formatted. * @param {string} unit – The unit to be appended to the formatted value. * @param {number} decimals – The number of decimal places to round the value to. * @returns {string} The formatted string representation of the value with unit. */ function customAxisFormatter(lang, value, unit, decimals) { /** * Check the language and format the value accordingly. * For French (fr) and German (de), use commas instead of dots. * For other languages (en), use the default format with dots. */ const formattedValue = lang === ‘fr’ || lang === ‘de’ ? `${value.toFixed(decimals).replace(‘.’, ‘,’)}${unit}` : `${value.toFixed(decimals)}${unit}`; return formattedValue; } /** * Enriches the x-axis labels with formatting based on certain values. * If EU and Euro Area are included, those must be written in bold * @remarks * This function enriches the x-axis labels with formatting based on certain values, such as making “EU” and “Euro Area” bold. * @param {object} option – The option object to set bold countries to. */ function boldCountries(option) { option.xAxis.axisLabel.formatter = function (v) { /** Convert input string to lowercase for case-insensitive comparison */ var lowerCaseV = v ? v.toLowerCase() : ”; /** Check for specific label values and format them accordingly, check for “EU” or “UE” */ if (lowerCaseV === “eu” || lowerCaseV === “ue”) { // return `{eu|${v}}`; } /** Check for “Euro Area”, “Euroraum”, or “Zone Euro” */ else if (lowerCaseV === “euro area” || lowerCaseV === “euroraum” || lowerCaseV === “zone euro”) { return `{euroArea|${v}}`; } return v; }; /** Set the rich property of the axis label to apply the bold formatting */ option.xAxis.axisLabel.rich = { eu: { fontWeight: “bold”, }, euroArea: { fontWeight: “bold” } }; } /** * Handles formatting the tooltip decimal convention in the graphic. * @remarks * This function formats the tooltip based on the language and decimal convention. * * @param {object} option – The option object to add custom tooltip. * @todo: Breaking it down into smaller functions could improve readability and maintainability. */ function setTooltipFormatter(option) { /** * Tooltip formatter for ECharts. * @param {object[]} params – Parameters for the tooltip formatter. * @param {string} params[].name – Name of the x-axis value. * @param {string} params[].seriesName – Name of the series. * @param {number} params[].value – Value of the data point. * @param {string} params[].color – Color of the series. * @param {string} ticket – Ticket for the callback. * @param {Function} callback – Callback function. * @returns {string} – Formatted tooltip content. */ option.tooltip.formatter = function (params, ticket, callback) { /** Create the tooltip content container with a white background and padding */ var tooltipContent = ”; /** Retrieve the x-axis value for the tooltip */ var xAxisValue = params[0].name; /** Add the x-axis value to the tooltip content */ /** @type {string} XAxis */ tooltipContent += ” + xAxisValue + ‘]]>

‘; /** Retrieve the order from the tooltip option */ var sortOrder = option.tooltip.order; /** Sort the ‘params’ array based on the ‘sortOrder’ parameter. */ switch (sortOrder) { /** Sort by series name in ascending order. */ case ‘seriesAsc’: params = params.sort((a, b) => a.seriesName.localeCompare(b.seriesName)); break; /** Sort by series name in descending order. */ case ‘seriesDesc’: params = params.sort((a, b) => b.seriesName.localeCompare(a.seriesName)); break; /** Sort by numerical value in ascending order. */ case ‘valueAsc’: params = params.sort((a, b) => parseFloat(a.value) – parseFloat(b.value)); break; /** Sort by numerical value in descending order. */ case ‘valueDesc’: params = params.sort((a, b) => parseFloat(b.value) – parseFloat(a.value)); break; /** Reverse the current order. */ case ‘reverse’: params.reverse(); break; default: break; } /** Iterate over each series in the tooltip parameters */ for (var i = 0; i -1) { /** Calculate the number of decimal places */ decimals = strValue.substring(strValue.indexOf(‘.’), strValue.length – 1).length; } else { /** If there are no decimal places, format the value with 1 decimal place */ decimals = decimals ? decimals : 1; /** Convert the value to a fixed-point notation string with a specified number of decimal places. */ value = Number(value).toFixed(decimals); } /** Convert -0 value to 0 with the specified or calculated number of decimal places.*/ if (Number(value) == -0) { value = (Number(value) + 0).toFixed(decimals); } /** Extract the unit from within the axis label */ var unit = axis.axisLabel.unit ? axis.axisLabel.unit : ”; /** Format the value using the appropriate number of decimal places */ value = isNaN(value) ? ‘N/A’ : Number(value).toLocaleString(option.lang ? option.lang : ‘en’, { minimumFractionDigits: decimals }) + unit; /** Retrieve the color of the current series */ const color = params[i].color; /** * Add the series name and value to the tooltip content * Use a circle icon with the series color */ tooltipContent += ‘

‘ + ” + ” + ” + seriesName + ” + ” + ” + value + ” + ‘

‘; } /** Close the tooltip content container */ tooltipContent += ”; /** Return the formatted tooltip content */ return tooltipContent; } } /* * This content is licensed according to the W3C Software License at * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document * * File: sortable-table.js * * Desc: Adds sorting to a HTML data table that implements ARIA Authoring Practices */ ‘use strict’; class SortableTable { constructor(tableNode) { this.tableNode = tableNode; this.columnHeaders = tableNode.querySelectorAll(‘thead th.sortable’); this.sortColumns = []; for (var i = 0; i b.value ? -1 : 1); } else { return isNumber ? a.value – b.value : (a.value

Subscribe to receive the latest Eurostat Euro indicators releases

{ if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(mutations => { if (document.querySelector(selector)) { resolve(document.querySelector(selector)); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } waitForElm(‘div.chart’).then((elm) => { // Has to be run after cool-ngx-editor.js script that is tweeking the charts const elements = document.getElementsByClassName(“chart”); for (let i = 0; i < elements.length; i++) { let div = document.createElement('div'); div.id = "share-chart-" + i; div.style = "position: absolute; right: 0; z-index: 50;"; elements[i].prepend(div); let script = document.createElement('script'); script.type = "application/json"; let url = new URL(window.location.href); url.searchParams.set('item', 'chart'); url.searchParams.set('id', i); let code = '{"service": "sbkm", "version": "2.0", "popup": false, "icon": true, "more" : ["facebook", "x", "linkedin", "email"], "renderTo": "' + div.id + '", "to": ["more"], "target": true, "link": "' + url.href + '", "via": "EU_Eurostat", "title": "' + getJournalArticleTitle() + '"}'; try { script.appendChild(document.createTextNode(code)); } catch (e) { s.text = code; } elements[i].parentNode.insertBefore(script, elements[i].nextSibling); } }); // Add share button to tables $(document).ready(function() { // Has to be run after cool-ngx-editor.js script that is tweeking the tables const tables = document.getElementsByTagName("table"); for (let i = 0; i position) { await new Promise(r => setTimeout(r, 500)); // Wait a bit so that it doesn’t scroll too far allItems[position].scrollIntoView(true); } } });;}());]]>