/* A-LINE standalone calculator. Generated by build-standalone.mjs. */ (()=>{ "use strict"; const defaults={price:4000,totalLoan:3600,fees:230,inspection:10,upgrade:60,savings:1200,term:35,method:'annuity',rate:1,rateMode:'variable',rates:[{year:6,rate:1.5},{year:11,rate:2},{year:21,rate:2.5}],income:40,partner:15,other:0,wage:1,partnerGrowth:1,otherGrowth:0,incomeChangeYear:21,incomeChange:0,life:25,education:3,educationEnd:15,inflation:2,tax:15,taxGrowth:0,insurance:5,management:0,reserve:0,parking:0,managementGrowth:2,property:'house',repairs:[{name:'給湯器・設備更新',year:10,amount:35},{name:'外壁・屋根のメンテナンス',year:15,amount:160},{name:'水回り・設備更新',year:20,amount:100},{name:'外壁・屋根のメンテナンス',year:30,amount:160}]}; function payment(p,r,n){if(p<=0||n<=0)return 0;return r===0?p/n:p*r/(1-Math.pow(1+r,-n));} function validate(s){const errors=[];const ranges={price:[0,100000],totalLoan:[0,130000],fees:[0,10000],inspection:[0,10000],upgrade:[0,10000],savings:[0,100000],term:[1,50],rate:[0,20],income:[0,1000],partner:[0,1000],other:[0,1000],wage:[-10,10],partnerGrowth:[-10,10],otherGrowth:[-10,10],incomeChangeYear:[1,50],incomeChange:[-1000,1000],life:[0,1000],education:[0,1000],educationEnd:[0,50],inflation:[-5,15],tax:[0,1000],taxGrowth:[-5,15],insurance:[0,1000],management:[0,1000],reserve:[0,1000],parking:[0,1000],managementGrowth:[-5,15]}; for(const [k,[min,max]] of Object.entries(ranges))if(!Number.isFinite(s[k])||s[k]max)errors.push(k); if(s.totalLoan>s.price+s.fees+s.inspection+s.upgrade+1e-8)errors.push('総借入額は購入総額以下にしてください。借り入れる諸費用・調査費・性能向上費も入力してください'); for(const k of ['term','incomeChangeYear','educationEnd'])if(!Number.isInteger(s[k]))errors.push(k+'は整数'); if(!['annuity','principal'].includes(s.method)||!['fixed','variable'].includes(s.rateMode))errors.push('返済方式'); const yrs=new Set();for(const x of s.rates){if(!Number.isInteger(x.year)||x.year<2||x.year>50||!Number.isFinite(x.rate)||x.rate<0||x.rate>20||yrs.has(x.year))errors.push('金利変更年は重複しない2〜50年、金利は0〜20%');yrs.add(x.year);} for(const x of s.repairs)if(!Number.isInteger(x.year)||x.year<1||x.year>50||!Number.isFinite(x.amount)||x.amount<0||x.amount>10000)errors.push('修繕は1〜50年、0〜10,000万円');return errors;} function simulate(s){const errors=validate(s);if(errors.length)throw new Error(errors.join(' / '));const Y=10000,acquisition=(s.price+s.fees+s.inspection+s.upgrade)*Y,p=s.totalLoan*Y,N=s.term*12,initial=Math.max(0,acquisition-p);let balance=p,cash=s.savings*Y-initial,rate=s.rate,pay=payment(p,rate/1200,N);const months=[],years=[];const changes=[...s.rates].sort((a,b)=>a.year-b.year); for(let m=1;m<=Math.max(360,N);m++){const year=Math.ceil(m/12),t=year-1;const newRate=s.rateMode==='fixed'?s.rate:changes.filter(x=>x.year<=year).at(-1)?.rate??s.rate; if(newRate!==rate){rate=newRate;pay=payment(balance,rate/1200,N-m+1);}const interest=m<=N?balance*rate/1200:0;const principal=m<=N?Math.min(balance,s.method==='principal'?p/N:Math.max(0,pay-interest)):0;const repayment=principal+interest;balance=Math.max(0,balance-principal);if(balance<0.00001)balance=0; const income=Math.max(0,s.income*Math.pow(1+s.wage/100,t)+s.partner*Math.pow(1+s.partnerGrowth/100,t)+s.other*Math.pow(1+s.otherGrowth/100,t)+(year>=s.incomeChangeYear?s.incomeChange:0))*Y; const inflation=Math.pow(1+s.inflation/100,t);const life=s.life*Y*inflation;const education=year<=s.educationEnd?s.education*Y*inflation:0;const tax=s.tax*Y*Math.pow(1+s.taxGrowth/100,t)/12,insurance=s.insurance*Y*inflation/12; const management=s.management*Y*Math.pow(1+s.managementGrowth/100,t),reserve=s.reserve*Y*Math.pow(1+s.managementGrowth/100,t),parking=s.parking*Y*inflation; const repair=m%12===0?s.repairs.filter(x=>x.year===year).reduce((a,x)=>a+x.amount*Y*inflation,0):0; const housing=repayment+tax+insurance+management+reserve+parking+repair,spending=housing+life+education,surplus=income-spending;cash+=surplus; months.push({m,year,rate,repayment,principal,interest,balance,income,life,education,tax,insurance,management,reserve,parking,repair,housing,spending,surplus,cash}); if(m%12===0){const rows=months.slice(-12),a={year,rate,balance,cash,monthlyPayment:rows[11].repayment};for(const k of ['repayment','principal','interest','income','life','education','tax','insurance','management','reserve','parking','repair','housing','spending','surplus'])a[k]=rows.reduce((sum,x)=>sum+x[k],0);years.push(a);}} const at=(h)=>{const rows=months.slice(0,h*12),sum=k=>rows.reduce((a,x)=>a+x[k],0);return{h,initial,principal:sum('principal'),interest:sum('interest'),repayment:sum('repayment'),holding:sum('tax')+sum('insurance')+sum('management')+sum('reserve')+sum('parking'),repair:sum('repair'),housing:initial+sum('housing'),life:sum('life')+sum('education'),income:sum('income'),balance:rows.at(-1).balance,cash:rows.at(-1).cash,minCash:Math.min(s.savings*Y-initial,...rows.map(x=>x.cash)),maxPayment:Math.max(...rows.map(x=>x.repayment)),firstDeficit:s.savings*Y-initial<0?0:rows.find(x=>x.cash<0)?.m??null};}; return{months,years,acquisition,initial,loan:p,openingCash:s.savings*Y-initial,firstPayment:months[0].repayment,lifetimeRepayment:months.slice(0,N).reduce((a,x)=>a+x.repayment,0),lifetimeInterest:months.slice(0,N).reduce((a,x)=>a+x.interest,0),at};} // Shared data charts and A4 report. All monetary values passed here are yen. const escapeText=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); const amount=(v,d=1)=>new Intl.NumberFormat('ja-JP',{maximumFractionDigits:d,minimumFractionDigits:d}).format(v/10000); const number=v=>new Intl.NumberFormat('ja-JP',{maximumFractionDigits:2}).format(v); function detailCharts(rows,monthly=false){ const names=rows.map(r=>monthly?((r.m-1)%12+1)+'月':r.year+'年'); const chart=(kind)=>{ const W=720,H=250,L=76,R=16,T=26,B=38,pw=W-L-R,ph=H-T-B,n=rows.length; const series=kind==='loan'?[['principal','元金','#0085c6'],['interest','利息','#e4a242']]:[['income','手取り収入','#0085c6'],['spending','総支出','#b66b38'],['surplus','家計収支','#6864a7']]; const values=kind==='loan'?rows.map(r=>r.repayment):rows.flatMap(r=>series.map(([k])=>r[k])); const low=Math.min(0,...values),high=Math.max(10000,...values),pad=(high-low)*.08,min=low<0?low-pad:0,max=high+pad; const y=v=>T+(max-v)/(max-min)*ph,x=i=>L+(i+.5)*pw/n; const title=kind==='loan'?'ローン返済の内訳':'収入・支出と家計収支'; let svg=`万円 / ${monthly?'月':'年'}`; for(let i=0;i<=4;i++){const v=min+(max-min)*i/4;svg+=`${amount(v,0)}`;} if(min<0)svg+=``; if(kind==='loan'){const bw=Math.min(32,pw/n*.64);rows.forEach((r,i)=>{let base=0;for(const [k,label,color]of series){svg+=`${names[i]} ${label} ${amount(r[k])}万円`;base+=r[k];}});}else{series.forEach(([k,label,color],j)=>{svg+=``;rows.forEach((r,i)=>{svg+=`${names[i]} ${label} ${amount(r[k])}万円`;});});} rows.forEach((r,i)=>{if(i===0||i===n-1||(i+1)%(n>20?5:n>12?2:1)===0)svg+=`${names[i]}`;}); return `

${title}

${svg}
${series.map(([k,label,color])=>`${label}${k==='surplus'?'(破線)':''}`).join('')}
`; }; return chart('loan')+chart('budget'); } function printReport(s,r,horizon,view,year,groups,overviewChart){ const a=r.at(horizon),monthly=view==='monthly',rows=monthly?r.months.filter(x=>x.year===year):r.years.slice(0,horizon),scope=monthly?year+'年目・月次(12か月)':horizon+'年間・年次'; const header=title=>`
A-LINE住まいの長期資金計画

${title}

`; const page=(title,content)=>``; const summary=[['購入総額',r.acquisition],['総借入額',r.loan],['購入時の自己資金',r.initial],['購入直後の金融資金',r.openingCash]]; const pairTable=pairs=>''+pairs.map(([label,value])=>``).join('')+'
${escapeText(label)}${value}
'; const compares=[10,20,30].map(h=>r.at(h)); const comparison=''+[['住まい総支出','housing'],['うち利息','interest'],['生活・教育費','life'],['手取り収入合計','income'],['ローン残高','balance'],['金融資金','cash']].map(([label,k])=>`${compares.map(v=>``).join('')}`).join('')+'
項目(万円)10年20年30年
${label}${amount(v[k])}
'; let out=page('試算結果のまとめ',`

表示期間:${horizon}年 / 明細:${scope} / 作成日:${new Date().toLocaleDateString('ja-JP')}

${horizon}年間の住まい総支出${amount(a.housing)}万円
当初の毎月返済額${amount(r.firstPayment)}万円
${horizon}年後の金融資金${amount(a.cash)}万円

購入時の資金内訳

${pairTable(summary.map(([l,v])=>[l,amount(v)+'万円']))}

購入時自己資金=購入総額-総借入額。購入総額には諸費用・調査・性能向上費を含みます。

金融資金とローン残高

${overviewChart}

実線:金融資金 / 破線:ローン残高

10年・20年・30年の比較

${comparison}

${a.firstDeficit===null?'この条件では、表示期間中の金融資金はマイナスになりません。':a.firstDeficit===0?'購入時に金融資金が不足します。':Math.ceil(a.firstDeficit/12)+'年目の'+((a.firstDeficit-1)%12+1)+'か月目に金融資金がマイナスになります。'} 期間内の最低金融資金:${amount(a.minCash)}万円。

`); const conditions=groups.map(([title,open,fields])=>'

'+escapeText(title)+'

'+pairTable(fields.map(([key,label,unit,options])=>[label,unit==='select'?escapeText(options.find(x=>x[0]===s[key])?.[1]??s[key]):number(s[key])+' '+unit]))+'
').join(''); const rateRows=(s.rateMode==='fixed'?[]:s.rates).map(x=>['金利変更:'+x.year+'年目から',number(x.rate)+'%']); out+=page('入力条件・メンテナンス計画',`
${conditions}

金利変更の予定

${rateRows.length?pairTable(rateRows):'

当初の年利を全期間適用。

'}

メンテナンス計画

${s.repairs.length?pairTable(s.repairs.map(x=>[x.year+'年目:'+x.name,number(x.amount)+'万円'])):'

設定なし

'}

修繕は現在価格。実施年までの物価上昇を加算。

`); out+=page('年次・月次のグラフ',`

${scope} / 単位:万円${monthly?' / 月':' / 年'}

${detailCharts(rows,monthly)}

総支出=ローン返済+税・保険・管理・修繕等+生活・教育費。購入時の自己資金 ${amount(r.initial)}万円は別計上。家計収支=手取り収入-総支出。

計算の前提

総借入額 ${amount(r.loan)}万円、${s.term}年返済、${s.method==='annuity'?'元利均等':'元金均等'}。完済までのローン総返済額 ${amount(r.lifetimeRepayment)}万円(うち利息 ${amount(r.lifetimeInterest)}万円)。表示期間の総支出とは集計範囲が異なります。

金利変更時に残高・残期間で返済額を再計算。5年・125%ルールは対象外。税・保険は月割り、修繕は指定年の12か月目。物価・収入の増加は2年目から年1回反映。控除・補助金・売却・運用益・繰上返済・ボーナス返済は含みません。初期値はサンプルであり、融資可否や将来額を保証しません。

`); const sets=[['返済・ローン残高',[['rate','年利 %'],['repayment','返済額'],['principal','元金'],['interest','利息'],['balance','期末残高']]],['家計・金融資金',[['income','手取り'],['life','生活費'],['education','教育等'],['spending','総支出'],['surplus','家計収支'],['cash','期末資金']]],['税・保険・管理・修繕',[['tax','税'],['insurance','保険'],['management','管理費'],['reserve','積立金'],['parking','駐車場'],['repair','個別修繕']]]]; for(const [title,cols]of sets){out+=page(title+'の明細',`

${scope} / 金額:万円 / 残高・金融資金は各${monthly?'月':'年'}末

${cols.map(x=>'').join('')}${rows.map(x=>`${cols.map(([k])=>``).join('')}`).join('')}
期間'+x[1]+'
${monthly?((x.m-1)%12+1)+'か月目':x.year+'年目'}${k==='rate'?number(x[k]):amount(x[k])}

購入時の自己資金 ${amount(r.initial)}万円は上表の支出に含めません。金融資金は購入直後の残額を起点に計算します。

`);} return out; } let state=structuredClone(defaults),horizon=30,view='annual',detailYear=1,result;const $=s=>document.querySelector(s);const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));const num=(n,d=0)=>new Intl.NumberFormat('ja-JP',{maximumFractionDigits:d,minimumFractionDigits:d}).format(n);const man=(n,d=0)=>num(n/10000,d);const money=n=>man(n,1)+'万円'; const groups=[ ['01 購入・総借入額',true,[['property','物件タイプ','select',[['house','戸建て'],['condo','マンション']]],['price','物件価格','万円',0,100000,50],['totalLoan','総借入額(諸費用分を含む)','万円',0,130000,10],['fees','購入諸費用','万円',0,10000,1],['inspection','建物状況調査','万円',0,10000,1],['upgrade','入居時の性能向上等','万円',0,10000,1],['savings','購入前の金融資金','万円',0,100000,10]],'総借入額は諸費用分も含めた借入希望額。自己資金は購入総額との差額から自動計算します。諸費用に調査・性能向上費を重複計上しないでください。借入全体に同じ金利・返済期間を適用します。'], ['02 ローン・金利',true,[['term','返済期間','年',1,50,1],['rate','当初の年利','%',0,20,.1],['method','返済方式','select',[['annuity','元利均等'],['principal','元金均等']]],['rateMode','金利の設定','select',[['variable','変更年を指定'],['fixed','全期間一定']]]],'金利変更年から新しい金利を適用。5年・125%ルールは使わず、返済額を即時見直します。'], ['03 手取り収入・成長率',false,[['income','本人の月収(手取り)','万円',0,1000,1],['wage','本人の年間増加率','%',-10,10,.1],['partner','配偶者等の月収(手取り)','万円',0,1000,1],['partnerGrowth','配偶者等の年間増加率','%',-10,10,.1],['other','その他の月収(手取り)','万円',0,1000,1],['otherGrowth','その他収入の年間増加率','%',-10,10,.1],['incomeChangeYear','家計収入の変更開始','年目',1,50,1],['incomeChange','開始後の月額増減','万円',-1000,1000,1]],'開始後の月額増減は、成長後の合計収入に固定額で加減。退職などの減収はマイナスを入力。合計収入の下限は0円。'], ['04 生活費・インフレ',false,[['life','月の基本生活費','万円',0,1000,1],['inflation','年間の物価上昇率','%',-5,15,.1],['education','月の教育・期間限定費','万円',0,1000,1],['educationEnd','期間限定費の終了','年目',0,50,1]],'基本生活費は食費・光熱費・通信・車・娯楽など。住宅費・教育費を含めず入力。終了年までは教育費を計上。'], ['05 保有・維持費',false,[['tax','固定資産税等(年額)','万円',0,1000,1],['taxGrowth','税額の年間増加率','%',-5,15,.1],['insurance','火災・地震保険(年額)','万円',0,1000,.1],['management','管理費(月額)','万円',0,1000,.1],['reserve','修繕積立金(月額)','万円',0,1000,.1],['managementGrowth','管理費・積立金の年増加率','%',-5,15,.1],['parking','駐車場(月額)','万円',0,1000,.1]],'税は独立した増加率、保険・駐車場は物価上昇率を適用。戸建ての自主的な修繕貯蓄は支出にせず、修繕年に計上。']]; function field(f){const[k,label,unit,min,max,step]=f;if(unit==='select')return `
`;return `
${unit}
`;} function renderInputs(){ $('#inputs').innerHTML=groups.map(([title,open,fs,hint],i)=>`
${title}
${fs.map(field).join('')}
${i===1?'
':''}

${hint}

`).join('')+`
06 メンテナンス計画

現在価格で入力。実施年の物価上昇を反映します。物件タイプ変更時は参考例に置き換わります。

`;renderEvents();} function renderEvents(){ $('#rate-events').innerHTML=state.rateMode==='variable'?'
適用開始年目年利 %
'+state.rates.map((r,i)=>`
金利変更 ${i+1}
`).join('')+'':'

全返済期間に当初金利を適用します。

'; $('#repair-events').innerHTML='
修繕の内容年目万円
'+state.repairs.map((r,i)=>`
`).join('')+'';} const colors=['#006b9e','#0085c6','#67b9ad','#a5b8c9','#daa856']; function update(){const errs=validate(state);$('#errors').hidden=!errs.length;$('#output').classList.toggle('invalid-output',!!errs.length);if(errs.length){$('#errors').textContent='入力を確認してください:'+errs.map(k=>groups.flatMap(x=>x[2]).find(f=>f[0]===k)?.[1]??k).join('、');return;}result=simulate(state);const a=result.at(horizon);$('#funding').innerHTML=`

購入時の資金内訳

${[['購入総額',result.acquisition],['総借入額',result.loan],['必要な自己資金',result.initial],['購入直後の金融資金',result.openingCash]].map(([label,value])=>`
${label}${money(value)}
`).join('')}

自己資金=物件価格+諸費用+調査・性能向上費-総借入額。諸費用の借入も含めて計算します。

`;$('#kpis').innerHTML=`
${horizon}年間の住まい総支出
${man(a.housing)}万円

購入時 ${man(a.initial)}万円 + 保有中 ${man(a.housing-a.initial)}万円

当初の毎月返済額
${man(result.firstPayment,1)}万円

期間内の最大返済額 ${money(a.maxPayment)} / 月

${horizon}年後の金融資金
${man(a.cash)}万円

ローン残高 ${man(a.balance)}万円(別途返済が必要)

`; let msg=a.firstDeficit===null?`この条件では${horizon}年間の金融資金はプラス。最も少ない時点は ${money(a.minCash)} です。`:`${a.firstDeficit===0?'購入時':Math.ceil(a.firstDeficit/12)+'年目・'+((a.firstDeficit-1)%12+1)+'か月目'}に金融資金がマイナスになります。最低額は ${money(a.minCash)}。総借入額・購入予算・生活費・収入を見直してください。`; $('#alert').innerHTML=`
${msg}
`; chart();const components=[['購入時の自己資金',a.initial],['ローン元金の返済',a.principal],['ローン利息',a.interest],['税・保険・管理等',a.holding],['個別修繕・設備交換',a.repair]];$('#cost-title').textContent=horizon+'年間の住まい総支出';$('#breakdown').innerHTML='
'+components.map(([_,v],i)=>``).join('')+'
'+components.map(([k,v],i)=>`
${k}${money(v)}
`).join('')+`
合計${money(a.housing)}
`; const sums=[10,20,30].map(h=>result.at(h));$('#compare').innerHTML=''+[['住まい総支出','housing'],['うち利息','interest'],['生活・教育費','life'],['手取り収入合計','income'],['ローン残高','balance'],['金融資金','cash']].map(([l,k])=>`${sums.map(x=>``).join('')}`).join('')+'
項目 / 万円10年20年30年
${l}${man(x[k])}
'; $('#assumptions').innerHTML=`

借入額 ${money(result.loan)} / ${state.term}年返済 / ${state.method==='annuity'?'元利均等':'元金均等'}。設定した金利推移による完済までのローン総返済額は ${money(result.lifetimeRepayment)}、うち利息は ${money(result.lifetimeInterest)}。10・20・30年時点の保有支出とは集計範囲が異なります。

仲介手数料無料の対象物件では、軽減できる額を購入諸費用に反映してください。残る金融資金を金利上昇・調査・性能向上・将来修繕への備えとして確認できます。

`; $('#detail-year').innerHTML=Array.from({length:horizon},(_,i)=>``).join('');renderTable();} function chart(){const data=[{year:0,cash:result.openingCash,balance:result.loan},...result.years.slice(0,horizon)];const w=780,h=275,L=70,R=18,T=18,B=38;let min=Math.min(0,...data.map(x=>x.cash)),max=Math.max(1000000,...data.map(x=>x.cash),result.loan);const padding=(max-min)*.08;max+=padding;if(min<0)min-=padding;const x=y=>L+y/horizon*(w-L-R),y=v=>T+(max-v)/(max-min)*(h-T-B);let svg=``;for(let i=0;i<5;i++){const v=min+(max-min)*i/4;svg+=`${man(v)}`;}svg+='万円';for(let i=0;i<=horizon;i+=5)svg+=`${i===0?'購入時':i+'年'}`;if(min<0)svg+=``; const path=k=>data.map((d,i)=>`${i?'L':'M'}${x(d.year)},${y(d[k])}`).join(' ');svg+=``;for(const d of data)svg+=`${d.year}年:金融資金 ${money(d.cash)} / 残高 ${money(d.balance)}`;$('#chart').innerHTML=svg+'';} const columns=[['repayment','返済額'],['principal','元金'],['interest','利息'],['balance','残高'],['income','手取り'],['life','生活費'],['education','教育等'],['tax','税'],['insurance','保険'],['management','管理費'],['reserve','積立金'],['parking','駐車場'],['repair','修繕'],['spending','総支出'],['surplus','家計収支'],['cash','金融資金']]; function renderTable(){if(!result)return;const rows=view==='annual'?result.years.slice(0,horizon):result.months.filter(x=>x.year===detailYear);$('#detail-charts').innerHTML=detailCharts(rows,view==='monthly');$('#detail-chart-scope').textContent=view==='annual'?horizon+'年間の年次推移(各年の合計)':detailYear+'年目の月次推移(各月の合計)';$('#detail-year-label').hidden=view!=='monthly';$('#details').innerHTML=''+columns.map(([k,t])=>``).join('')+''+rows.map(r=>`${columns.map(([k])=>``).join('')}`).join('')+'
単位:万円。総支出は保有中の住居費+生活・教育費。購入時 '+money(result.initial)+' は別計上。
期間年利 %${t}${view==='annual'&&k==='repayment'?' / 年':''}
${view==='annual'?r.year+'年目':((r.m-1)%12+1)+'か月目'}${num(r.rate,2)}${man(r[k],1)}
';} $('#inputs').addEventListener('input',e=>{const el=e.target;if(el.dataset.key){const k=el.dataset.key;state[k]=el.tagName==='SELECT'?el.value:el.value===''?NaN:Number(el.value);if(k==='rateMode')renderEvents();if(k==='property'){if(el.value==='condo'){state.management=1.5;state.reserve=1.5;state.parking=1;state.repairs=[{name:'専有部設備更新',year:10,amount:35},{name:'水回り・内装更新',year:20,amount:150}];}else{state.management=0;state.reserve=0;state.parking=0;state.repairs=structuredClone(defaults.repairs);}for(const key of ['management','reserve','parking'])$('#'+key).value=state[key];renderEvents();}}else if(el.dataset.rate!==undefined)state.rates[+el.dataset.rate][el.dataset.prop]=el.value===''?NaN:Number(el.value);else if(el.dataset.repair!==undefined)state.repairs[+el.dataset.repair][el.dataset.prop]=el.dataset.prop==='name'?el.value:el.value===''?NaN:Number(el.value);else return;document.querySelectorAll('[data-preset]').forEach(x=>x.classList.remove('selected'));update();}); $('#inputs').addEventListener('click',e=>{const el=e.target;if(el.id==='add-rate'){const taken=state.rates.map(r=>r.year);let year=2;while(taken.includes(year)&&year<=50)year++;if(year<=50)state.rates.push({year,rate:state.rate});}else if(el.id==='add-repair')state.repairs.push({name:'追加メンテナンス',year:15,amount:50});else if(el.dataset.removeRate!==undefined)state.rates.splice(+el.dataset.removeRate,1);else if(el.dataset.removeRepair!==undefined)state.repairs.splice(+el.dataset.removeRepair,1);else return;renderEvents();update();}); document.querySelectorAll('[data-h]').forEach(b=>b.onclick=()=>{horizon=+b.dataset.h;detailYear=Math.min(detailYear,horizon);document.querySelectorAll('[data-h]').forEach(x=>x.classList.toggle('active',x===b));update();});document.querySelectorAll('[data-view]').forEach(b=>b.onclick=()=>{view=b.dataset.view;document.querySelectorAll('[data-view]').forEach(x=>x.classList.toggle('active',x===b));renderTable();});$('#detail-year').onchange=e=>{detailYear=+e.target.value;renderTable();}; document.querySelectorAll('[data-preset]').forEach(b=>b.onclick=()=>{const p=b.dataset.preset;state=structuredClone(defaults);if(p==='stress'){state.rates=[{year:6,rate:2},{year:11,rate:3},{year:21,rate:4}];state.inflation=3;state.wage=0;state.partnerGrowth=0;}if(p==='growth'){state.wage=3;state.partnerGrowth=2;state.inflation=2;}document.querySelectorAll('[data-preset]').forEach(x=>x.classList.toggle('selected',x===b));renderInputs();update();}); $('#reset').onclick=()=>document.querySelector('[data-preset="base"]').click(); function preparePrint(){if(validate(state).length){$('#print-report').innerHTML='

入力にエラーがあります。条件を修正してから印刷してください。

';return false;}$('#print-report').innerHTML=printReport(state,result,horizon,view,detailYear,groups,$('#chart').innerHTML);return true;} window.addEventListener('beforeprint',preparePrint); for(const id of ['print','print-detail'])$('#'+id).onclick=()=>{if(preparePrint())window.print();}; $('#csv').onclick=()=>{if(validate(state).length)return;const lines=[['A-LINE 住宅保有シミュレーション','単位:円 / 年利:%'],['購入時支出',Math.round(result.initial)],['購入後金融資金',Math.round(result.openingCash)],['購入総額',result.acquisition],['総借入額',result.loan],['入力条件(万円・%)',JSON.stringify(state)],['経過月','年目','年利',...columns.map(x=>x[1])],...result.months.slice(0,horizon*12).map(r=>[r.m,r.year,r.rate,...columns.map(([k])=>Math.round(r[k]))])];const text='\uFEFF'+lines.map(r=>r.map(v=>'"'+String(v).replaceAll('"','""')+'"').join(',')).join('\r\n');const url=URL.createObjectURL(new Blob([text],{type:'text/csv;charset=utf-8'}));const a=document.createElement('a');a.href=url;a.download=`A-LINE_${horizon}年_返済家計シミュレーション.csv`;a.click();setTimeout(()=>URL.revokeObjectURL(url),1000);}; renderInputs();if(window.matchMedia('(max-width: 800px)').matches)document.querySelectorAll('.input-section').forEach(x=>x.open=false);update(); if(document.modelContext?.registerTool){const lifecycle=new AbortController();try{Promise.resolve(document.modelContext.registerTool({name:'read_home_cost_simulation',description:'現在画面に設定した住宅ローンと家計の10年・20年・30年試算結果を取得する。金額は円。',inputSchema:{type:'object',properties:{},additionalProperties:false},annotations:{readOnlyHint:true},execute(input){if(input===null||typeof input!=='object'||Object.keys(input).length)throw Error('空のオブジェクトを指定してください');if(validate(state).length)throw Error('入力条件にエラーがあります');return{assumptions:state,periods:[10,20,30].map(h=>result.at(h))};}},{signal:lifecycle.signal})).catch(()=>{});window.addEventListener('pagehide',()=>lifecycle.abort(),{once:true});}catch{}} if(new URLSearchParams(location.search).get('embed')==='1'){ document.documentElement.classList.add('embedded'); let parentOrigin=null; try{const origin=new URL(document.referrer).origin;if([location.origin,'https://www.a-l-i-n-e.jp','https://a-l-i-n-e.jp'].includes(origin))parentOrigin=origin;}catch{} if(parentOrigin&&window.parent!==window){let previous=0;const reportHeight=()=>{const height=Math.ceil(document.querySelector('main').getBoundingClientRect().height)+32;if(height!==previous){previous=height;window.parent.postMessage({type:'aline-simulator:resize',height},parentOrigin);}};new ResizeObserver(reportHeight).observe(document.querySelector('main'));reportHeight();} } })();