Ny visualisering: hvem eier egentlig boligen din? SSB-data 2015–2024

Tre diagrammer basert på SSB-tabellene 14068, 14059 og 14065:
- Kakediagram: 34 % eier fritt, 38 % eier med banklån, 28 % leier
- Stablet stolpe: gjeldsbyrde over tid (lån >3M tredoblet seg)
- Horisontal stablet: eierskap etter husholdningstype (65 % av unge leier)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2026-03-16 19:52:47 +01:00
commit 4f82236b8b
4 changed files with 491 additions and 0 deletions

248
public/boligeierskap/app.js Normal file
View file

@ -0,0 +1,248 @@
// SSB data: Boligeierskap og boligøkonomi
// Tabell 14068: Boligeierskap etter husholdningstype (prosent)
// Tabell 14059: Boligøkonomi etter eierstatus (gjeldsstørrelse)
// Tabell 14065: Boliglån og boligutgifter (gjeld vs verdi)
// Hentet 2026-03-16 via SSB PxWeb API v2
// --- Data ---
// Eierskap alle husholdninger 2024 (tabell 14068):
// Selveier 57.5%, Andelseier 14.8%, Leier 27.7%
// Total eiere = 72.3%
// Av eiere uten boliglån: 47.6% (tabell 14059, 2024)
// Eier fritt = 72.3 × 0.476 = 34.4%
// Eier med lån = 72.3 × 0.524 = 37.9%
// Gjeldsstørrelse blant eiere med lån (tabell 14059, "I alt")
const YEARS = ['2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024'];
const LOAN_DIST = {
under1M: [17.2, 15.3, 13.9, 13.5, 13.2, 12.7, 13.6, 12.4, 11.7, 12.1],
from1to2M:[17.0, 16.8, 16.2, 15.1, 14.9, 14.9, 14.2, 14.8, 14.4, 14.8],
from2to3M:[ 8.2, 9.7, 10.0, 9.7, 10.3, 10.5, 12.1, 12.1, 11.9, 11.8],
over3M: [ 4.5, 5.1, 6.2, 6.8, 8.1, 8.9, 10.9, 12.0, 12.2, 13.8]
};
// Eierskap etter husholdningstype 2024 (tabell 14068)
const HOUSEHOLD_TYPES = [
{ name: 'Aleneboende 1644', selveier: 20.7, andel: 13.8, leier: 65.5 },
{ name: 'Par uten barn 1644', selveier: 41.6, andel: 21.8, leier: 36.6 },
{ name: 'Enslige forsørgere 017', selveier: 50.1, andel: 11.6, leier: 38.3 },
{ name: 'Aleneboende 4566', selveier: 54.7, andel: 17.2, leier: 28.1 },
{ name: 'Aleneboende 67+', selveier: 60.0, andel: 23.0, leier: 17.0 },
{ name: 'Par med barn 06', selveier: 70.8, andel: 12.1, leier: 17.1 },
{ name: 'Par uten barn 67+', selveier: 78.7, andel: 15.2, leier: 6.1 },
{ name: 'Par med barn 717', selveier: 82.9, andel: 8.2, leier: 8.8 },
{ name: 'Par uten barn 4566', selveier: 82.2, andel: 11.6, leier: 6.1 },
{ name: 'Par med barn 18+', selveier: 87.7, andel: 6.8, leier: 5.6 },
];
// --- Formattering ---
function fmtPct(n) {
return n.toLocaleString('nb-NO', { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + '\u202f%';
}
const GRID_COLOR = 'rgba(0,0,0,0.06)';
const TICK_COLOR = '#8a857e';
function baseOpts() {
return {
responsive: true, maintainAspectRatio: false,
plugins: {
legend: { display: false },
tooltip: {
backgroundColor: '#1a1714',
titleColor: '#f5f2eb',
bodyColor: 'rgba(245,242,235,0.7)',
padding: 10,
cornerRadius: 4,
titleFont: { family: 'DM Sans', size: 12 },
bodyFont: { family: 'DM Sans', size: 12 }
}
},
scales: {
x: {
ticks: { color: TICK_COLOR, font: { size: 11, family: 'DM Sans' }, maxRotation: 0 },
grid: { display: false },
border: { color: 'rgba(0,0,0,0.1)' }
},
y: {
ticks: { color: TICK_COLOR, font: { size: 11, family: 'DM Sans' }, callback: v => v + ' %' },
grid: { color: GRID_COLOR },
border: { dash: [3, 3], color: 'transparent' }
}
}
};
}
// --- Diagram 1: Kakediagram (doughnut) ---
new Chart(document.getElementById('chart1'), {
type: 'doughnut',
data: {
labels: ['Eier fritt (34 %)', 'Eier med lån (38 %)', 'Leier (28 %)'],
datasets: [{
data: [34.4, 37.9, 27.7],
backgroundColor: ['#2c6e49', '#1a4a8a', '#c0392b'],
borderColor: '#fff',
borderWidth: 3,
hoverOffset: 8
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
cutout: '55%',
plugins: {
legend: { display: false },
tooltip: {
callbacks: {
label: function(c) {
return ' ' + c.label + ': ' + fmtPct(c.parsed);
}
},
backgroundColor: '#1a1714',
titleColor: '#f5f2eb',
bodyColor: 'rgba(245,242,235,0.7)',
padding: 10,
cornerRadius: 4,
titleFont: { family: 'DM Sans', size: 12 },
bodyFont: { family: 'DM Sans', size: 12 }
}
}
}
});
// --- Diagram 2: Gjeldsbyrde over tid (stablet stolpe) ---
var chart2Opts = baseOpts();
chart2Opts.scales.y.stacked = true;
chart2Opts.scales.x.stacked = true;
chart2Opts.scales.y.max = 55;
chart2Opts.plugins.tooltip = {
mode: 'index',
callbacks: {
label: function(c) {
return ' ' + c.dataset.label + ': ' + fmtPct(c.parsed.y);
}
},
backgroundColor: '#1a1714',
titleColor: '#f5f2eb',
bodyColor: 'rgba(245,242,235,0.7)',
padding: 10,
cornerRadius: 4,
titleFont: { family: 'DM Sans', size: 12 },
bodyFont: { family: 'DM Sans', size: 12 }
};
new Chart(document.getElementById('chart2'), {
type: 'bar',
data: {
labels: YEARS,
datasets: [
{
label: 'Under 1 mill',
data: LOAN_DIST.under1M,
backgroundColor: '#27ae60cc',
borderColor: '#27ae60',
borderWidth: 1,
borderRadius: 1
},
{
label: '12 mill',
data: LOAN_DIST.from1to2M,
backgroundColor: '#e67e22cc',
borderColor: '#e67e22',
borderWidth: 1,
borderRadius: 1
},
{
label: '23 mill',
data: LOAN_DIST.from2to3M,
backgroundColor: '#e74c3ccc',
borderColor: '#e74c3c',
borderWidth: 1,
borderRadius: 1
},
{
label: 'Over 3 mill',
data: LOAN_DIST.over3M,
backgroundColor: '#8b1a1acc',
borderColor: '#8b1a1a',
borderWidth: 1,
borderRadius: 1
}
]
},
options: chart2Opts
});
// --- Diagram 3: Eierskap etter livssituasjon (horisontal stablet) ---
var chart3Opts = baseOpts();
chart3Opts.indexAxis = 'y';
chart3Opts.scales = {
x: {
stacked: true,
max: 100,
ticks: { color: TICK_COLOR, font: { size: 11, family: 'DM Sans' }, callback: v => v + ' %' },
grid: { color: GRID_COLOR },
border: { dash: [3, 3], color: 'transparent' }
},
y: {
stacked: true,
ticks: { color: TICK_COLOR, font: { size: 11, family: 'DM Sans' }, autoSkip: false },
grid: { display: false },
border: { color: 'rgba(0,0,0,0.1)' }
}
};
chart3Opts.plugins.tooltip = {
mode: 'index',
callbacks: {
label: function(c) {
return ' ' + c.dataset.label + ': ' + fmtPct(c.parsed.x);
}
},
backgroundColor: '#1a1714',
titleColor: '#f5f2eb',
bodyColor: 'rgba(245,242,235,0.7)',
padding: 10,
cornerRadius: 4,
titleFont: { family: 'DM Sans', size: 12 },
bodyFont: { family: 'DM Sans', size: 12 }
};
new Chart(document.getElementById('chart3'), {
type: 'bar',
data: {
labels: HOUSEHOLD_TYPES.map(h => h.name),
datasets: [
{
label: 'Selveier',
data: HOUSEHOLD_TYPES.map(h => h.selveier),
backgroundColor: '#2c6e49cc',
borderColor: '#2c6e49',
borderWidth: 1,
borderRadius: 2
},
{
label: 'Andelseier',
data: HOUSEHOLD_TYPES.map(h => h.andel),
backgroundColor: '#1a4a8acc',
borderColor: '#1a4a8a',
borderWidth: 1,
borderRadius: 2
},
{
label: 'Leier',
data: HOUSEHOLD_TYPES.map(h => h.leier),
backgroundColor: '#c0392bcc',
borderColor: '#c0392b',
borderWidth: 1,
borderRadius: 2
}
]
},
options: chart3Opts
});