From e8f552ea112013fbb9d1e36b39f2fa68e30b264c Mon Sep 17 00:00:00 2001 From: tmarumo0831 <90425151+tmarumo0831@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:35:35 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF=E3=82=B7?= =?UTF-8?q?=E3=83=BC=E3=83=88=E3=81=ABCSV=E5=85=A5=E5=87=BA=E5=8A=9B?= =?UTF-8?q?=E6=A9=9F=E8=83=BD=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/checksheet.html | 522 +++--------- docs/io.js | 1841 ++++++++++++++++++++++++------------------ docs/subjects.js | 2 - docs/update.js | 968 ++++++++++------------ 4 files changed, 1618 insertions(+), 1715 deletions(-) diff --git a/docs/checksheet.html b/docs/checksheet.html index 6f397c4..c630b2c 100644 --- a/docs/checksheet.html +++ b/docs/checksheet.html @@ -1,5 +1,5 @@ - + @@ -11,129 +11,66 @@ gtag('config', 'G-9W0RED852G'); + + + + + + + + + + + 卒業要件チェックシート - - - - @@ -235,6 +183,7 @@ +
@@ -242,27 +191,27 @@
- - +
- - @@ -278,7 +227,7 @@
- + @@ -292,13 +241,16 @@
受講時期
-
+ + +
+
- +
@@ -310,7 +262,7 @@ - + @@ -323,7 +275,10 @@ -
受講時期形態
+ + + +
@@ -334,27 +289,27 @@
- - +
- - @@ -380,93 +335,7 @@ 科目数 - - - 総 - 認定 - 0 - - - - - - - 人文 - - - - - - - - 社会 - - - - - - - - 科学 - - - - - - - - 統計 - - - - - - - 必語 - - - - - - - 他語 - - - - - - - 保体 - - - - - - 専 - 必修 - - - - - - - 選必 - - - - - - - 選択 - - - - - - 論 - 卒論 - - +
@@ -484,180 +353,30 @@ 詳 細 取得 登録 - 申告 - 提出 - 卒業 + 申告 + 提出 + 卒業 進捗 - - - 総 - 3分 - 0 - 28 - - - 0 - 0% - - - 総 - 人文 - 0 - - - - 0 - 0% - - - 総 - 社会 - 0 - - - - 0 - 0% - - - 総 - 科学 - 0 - - - - 0 - 0% - - - 総 - 統計T - 0 - - - - 0 - 0% - - - 総 - 3分T - 0 - 18 - - - 0 - 0% - - - 総 - 外語 - 0 - 6 - - - 0 - 0% - - - 総 - 計 - 0 - 36 - 48 - 48 - 0 - 0% - - - 専 - 必修 - 0 - - 10 - - 0 - 0% - - - 専 - 選必 - 0 - - - - 0 - 0% - - - 専 - 通信 - 0 - - - - 0 - 0% - - - 専 - 計 - 0 - 7 - 35 - 60 - 0 - 0% - - - 計 - 通信 - 0 - - - - 0 - 0% - - - 計 - スク - 0 - - - - 0 - 0% - - - 論 - 卒論 - 0 - - - - 0 - 0% - +
-
-
-
+
+
+
0

-
-
-
0
+
+
+
0
@@ -671,27 +390,28 @@

- - + +
-

入力上の注意

-

※1:認定単位には仮認定は含みません

-

※2:統計学の認定単位の有無は入学時の成績証明書を確認下さい

-

※3:外国語の認定単位は慶應通信/通学卒業者のみ認定されます

-

※4:自然科学の単位は統計学を含んだ単位数で入力下さい

+

入力上の注意

+
    +
  1. 認定単位には仮認定は含みません
  2. +
  3. 統計学の認定単位の有無は入学時の成績証明書を確認下さい
  4. +
  5. 外国語の認定単位は慶應通信/通学卒業者のみ認定されます
  6. +
  7. 自然科学の単位は統計学を含んだ単位数で入力下さい
  8. +

-

このツールで判定できない卒業要件

-

※1:必修外国語の組み合わせを判定しません

-

※2:重複履修等で無効になる単位数を判定しません

-

※3:特別課程で認定単位がある場合に保健体育などで上限を超過する単位数を判定しません

- - - +

このツールで判定できない卒業要件

+
    +
  1. 必修外国語の組み合わせを判定しません
  2. +
  3. 重複履修等で無効になる単位数を判定しません
  4. +
  5. 特別課程で認定単位がある場合に保健体育などで上限を超過する単位数を判定しません
  6. +
\ No newline at end of file diff --git a/docs/io.js b/docs/io.js index 954301f..7ffc5b2 100644 --- a/docs/io.js +++ b/docs/io.js @@ -1,820 +1,1113 @@ /* ToDo --[] スクーリングの処理作成 --[] スクーリングマスター作成 +-[x] スクーリングの処理作成 +-[x] スクーリングマスター作成 -[] スクーリングの際にレポ合否を判定しない処理を追加 */ -const grades = Array.from({ length: 12 }, () => Array(3).fill(0)); +const units = Array.from({ length: 12 }, () => Array(3).fill(0)); var subjNum = new Array(5).fill(0); -var deptLabel = '-'; -var sectLabel = '-'; -var courseLabel = '-'; -var termLabel = []; const maxYear = 21; -const cols = 6; -const rows = maxYear*cols; -const reptRow = 6; -const Now = 2024; -const subCateOptions = ['人文', '社会', '科学', '統計', '必語', '他語', '保体', '必修', '選必', '選択']; -const formOptions = ['T', 'S', 'M/B']; - +const groups = 6; +const eventPerYear = 6; +const PlanningRows = maxYear*eventPerYear; +const profile = { + Element1:{year: null, month: null, department: null, section: null, course: null, language: null, stat: null, appLang: null, years: null, months: null}, + Element2:{year: null, month: null, department: null, section: null, course: null, language: null, stat: null, appLang: null, years: null, months: null}, + value :{year: null, month: null, department: null, section: null, course: null, language: null, stat: null, appLang: null, years: null, months: null}, +} +const elements = [ + { prefix: 'Arts1', index: 1 }, + { prefix: 'Arts2', index: 2 }, + { prefix: 'Arts3', index: 3 }, + { prefix: 'Stat', index: 4 }, + { prefix: 'FL1', index: 5 }, + { prefix: 'FL2', index: 6 }, + { prefix: 'Sports', index: 7 }, + { prefix: 'Required', index: 8 }, + { prefix: 'Elective1', index: 9 }, + { prefix: 'Elective2', index: 10 }, + { prefix: 'Thesis', index: 11 } +]; +const labels = {dept: '-', sect: '-', course: '-', }; +var entries = []; document.addEventListener("DOMContentLoaded", function() { - const sections = { - '文学部': ['第1類', '第2類', '第3類'], - '経済学部': [''], - '法学部': ['甲類', '乙類'], - }; - var depCategories = [""]; - var initLevel = 0; - - const year1 = document.getElementById('year_1'); - const month1 = document.getElementById('month_1'); - const departmentSelect1 = document.getElementById('department_1'); - const sectionSelect1 = document.getElementById('section_1'); - const courseSelect1 = document.getElementById('course_1'); - const language1 = document.getElementById('language_1'); - const stat1 = document.getElementById('apply_stat_1'); - const aplang1 = document.getElementById('apply_fl1_1'); - const year = document.getElementById('year'); - const month = document.getElementById('month'); - const departmentSelect = document.getElementById('department'); - const sectionSelect = document.getElementById('section'); - const courseSelect = document.getElementById('course'); - const language = document.getElementById('language'); - const stat = document.getElementById('apply_stat'); - const aplang = document.getElementById('apply_fl1'); - const years = document.getElementById('years'); - const months = document.getElementById('months'); - var dispterm = 0; // 表示するドロップダウンリストの数 - const tableBody = document.querySelector('#dropdownTable tbody'); - - year1.addEventListener('input', function() { - year.value = year1.value; - updateTermLabel(); - initPlanSheet(); - }); - year.addEventListener('input', function() { - year1.value = year.value; - updateTermLabel(); - initPlanSheet(); - }); - month1.addEventListener('change', function() { - month.value = month1.value; - updateTermLabel(); - initPlanSheet(); - }); - month.addEventListener('change', function() { - month1.value = month.value; - updateTermLabel(); - initPlanSheet(); - }); - departmentSelect1.addEventListener('change', function() { - departmentSelect.value = departmentSelect1.value; - updateSections(); - updateFilter(); - initPlanSheet(); - updateSelectedValuesTable(); - }); - departmentSelect.addEventListener('change', function() { - departmentSelect1.value = departmentSelect.value; - updateSections(); - updateFilter(); - initPlanSheet(); - updateSelectedValuesTable(); - }); - sectionSelect1.addEventListener('change', function() { - sectionSelect.value = sectionSelect1.value; - changeValue(); - updateFilter(); - initPlanSheet(); - updateSelectedValuesTable(); - }); - sectionSelect.addEventListener('change', function() { - sectionSelect1.value = sectionSelect.value; - changeValue(); - updateFilter(); - initPlanSheet(); - updateSelectedValuesTable(); - }); - courseSelect1.addEventListener('change', function() { - courseSelect.value = courseSelect1.value; - changeValue(); - updateFilter(); - initPlanSheet(); - updateSelectedValuesTable(); - }); - courseSelect.addEventListener('change', function() { - courseSelect1.value = courseSelect.value; - changeValue(); - updateFilter(); - initPlanSheet(); - updateSelectedValuesTable(); - }); - language1.addEventListener('change', function() { - language.value = language1.value; - initPlanSheet(); - updateSelectedValuesTable(); - }); - language.addEventListener('change', function() { - language1.value = language.value; - initPlanSheet(); - updateSelectedValuesTable(); - }); - stat1.addEventListener('change', function() { - stat.checked = stat1.checked; - changeValue(); - }); - stat.addEventListener('change', function() { - stat1.checked = stat.checked; - changeValue(); - }); - aplang1.addEventListener('change', function() { - aplang.checked = aplang1.checked; - changeValue(); - }); - aplang.addEventListener('change', function() { - aplang1.checked = aplang.checked; - changeValue(); - }); - years.addEventListener('change', function() { - dispterm = parseInt(years.value * 2 + months.value/6)*3; - updatePlanSheet(); - }); - months.addEventListener('change', function() { - dispterm = parseInt(years.value * 2 + months.value/6)*3; - updatePlanSheet(); - }); + initializeTables(); + setupEventListeners(); + refresh('byCourse'); +}); - window.updateSections = function() { - const department = departmentSelect.value; - const scts = sections[department] || []; - const html = scts.map(function(sct) { - return ''; - }).join(''); - sectionSelect.innerHTML = html; - sectionSelect1.innerHTML = html; - changeValue(); - } +function writePlanningTable() { + function getVisibleRows() { + const rows = document.querySelectorAll('#ActualBody tr'); // #ActualBody 内のすべての tr 要素を取得 + const visibleRows = Array.from(rows).filter(row => !row.classList.contains('hidden')); // hidden クラスを持たない行をフィルタリング + return visibleRows; + } + const getGroup = (rowId) => { + const groupMap = {'0':'A群','1':'B群','2':'C群','3':'D群','4':'E群','5':'F群'}; + const lastChar = rowId.slice(-1); + return groupMap[lastChar] || ''; + } + const visibleRows = getVisibleRows(); + const csvRows = []; - function filterTerms(year, term, pattern) { - const isOdd = parseInt(year)% 2 === 1; - switch (pattern){ - case 'Both': - result = true; - break; - case 'A': - result = term == 'A'; - break; - case 'B': - result = term == 'B'; - break; - case 'OddA': - result = (isOdd && term == 'A')||(!isOdd && term == 'B'); - break; - case 'OddB': - result = (isOdd && term == 'B')||(!isOdd && term == 'A'); - break; - } - return result; - } + csvRows.push('受講時期,群,科目名,評価,レポ合否,単位数,区分,形態'); - function filterSchedule(year, term, group, schedule) { - if(year < 2019 || year > Now){ - return true; - } - if (!Array.isArray(schedule)) { - return false; - } - const foundItem = schedule.find(item => - Array.isArray(item) && item.length >= 3 && item[0] === year && item[1] === term && item[2] === group - ); - return foundItem ? true : false; - } + visibleRows.forEach(row => { + const examName = row.querySelector('.examName').textContent; + const groupName = getGroup(row.id); + const subjectName = row.querySelector('.subjectName').textContent; + const gradeReport = row.querySelector('.radio-group input[type="radio"]:checked').value; + const unit = row.querySelector('.unit-input').value; + const gradeExam = row.querySelector('.dropdown').value; + const subCategory = row.querySelector('.subDropdown').value; + const subForm = row.querySelector('.formDropdown').value; + console.log(examName,groupName,subjectName,gradeExam,gradeReport,unit,subCategory,subForm); + csvRows.push([ + examName, + groupName, + subjectName, + gradeExam, + gradeReport, + unit, + subCategory, + subForm + ].map(cell => `"${cell.replace(/"/g, '""')}"`).join(',')); + }); + // CSVデータを文字列として作成 + const csvString = csvRows.join('\n'); + + // UTF-8 with BOM + const bom = '\uFEFF'; // BOM + const csvWithBom = bom + csvString; - function filterOptionsByCategories(options, categories, maxLevel, group, year, term) { - return options.filter(option => - option.category.some(cat => categories.includes(cat)) && - option.level <= maxLevel && - (option.group ? option.group === group || option.group === '' : true) && - (option.start ? option.start <= year && option.end >= year : true) && - (option.pattern ? filterTerms(year, term, option.pattern): true) && - (option.schedule ? filterSchedule(year, term, group, option.schedule): true) && -// (option.term && Array.isArray(option.term) ? option.term.some(t => t === term) : true) && - (option.filter ? option.filter(categories, year, term) : true)&& - (option.COVID19filter ? option.COVID19filter(year, term, group) : true) - ); - } - - function checkSubcategory(subcategory){ - let result = []; - switch (subcategory) { - case 'any': - result = ['人文', '社会', '科学', '統計', '必語', '他語', '保体', '必修', '選必', '選択', '自由']; - break; - case '人文': - case '社会': - case '科学': - case '統計': - case '他語': - case '保体': - case '必修': - case '選必': - case '選択': - result[0] = subcategory; - break; - case '英': - result[0] = (language.value == '英語') ? '必語':'他語'; - break; - case '独': - result[0] = (language.value == 'ドイツ語') ? '必語':'他語'; - break; - case '仏': - result[0] = (language.value == 'フランス語') ? '必語':'他語'; - break; - case '1類': - result[0] = (sectionSelect.value == '第1類') ? '必修':'選択'; - break; - case '2類': - result[0] = (sectionSelect.value == '第2類') ? '必修':'選択'; - break; - case '3類': - result[0] = (sectionSelect.value == '第3類') ? '必修':'選択'; - break; - case '共通': - result[0] = (departmentSelect .value == '文学部') ? '必修':'選択'; - break; - } - return JSON.stringify(result); - } + // プレビュー用のテキストエリアを作成 + const previewWindow = window.open('', 'CSV Preview', 'width=600,height=400'); + previewWindow.document.write('CSV Preview'); + previewWindow.document.write('

CSV Preview

'); + previewWindow.document.write(''); + previewWindow.document.write('
'); + previewWindow.document.write('
'); + previewWindow.document.write(''); + previewWindow.document.write(''); + previewWindow.document.close(); +}; - function checkForm(form){ - let result = []; - switch (form) { - case 'any': - result = ['T', 'S', 'M/B']; - break; - default: - result[0] = form; - break; - } - return JSON.stringify(result); - } +function readPlanningTable() { + function inputName(i, j, name) { + const select = document.getElementById(`subject-${i}-${j}`); + if (select) { + select.value = name; + } + } + function inputGrade(i, j, name, gradeExam, gradeReport, unit, subCategory, subForm) { + function selectRadioButton(selectRow, valueToSelect) { + // ラジオボタンの親要素を取得 + const radioGroup = selectRow.querySelector('.radio-group'); + if (!radioGroup) return; // 親要素が存在しない場合は何もせずに終了 + const radioButtons = radioGroup.querySelectorAll('input[type="radio"]'); + radioButtons.forEach(radio => { + if (radio.value === valueToSelect) { + radio.checked = true; + } + }); + } - function createDropdown(options) { - const select = document.createElement('select'); - options.forEach(option => { - const opt = document.createElement('option'); - opt.value = option.value; - opt.textContent = option.value; - opt.dataset.unit = option.unit; - let subCat; - if (Array.isArray(option.subcategory)) { - subCat = sectionSelect.value === '甲類' ? option.subcategory[0] : option.subcategory[1]; - } else { - subCat = option.subcategory; - } - opt.dataset.subcategory = checkSubcategory(subCat); - opt.dataset.form = checkForm(option.form); - select.appendChild(opt); - }); - return select; - } + const selectRow = document.getElementById(`actual-${i}-${j}`); + const subjectName = selectRow.querySelector('.subjectName').textContent; - function createDropdown2(options) { - const select = document.createElement('select'); - options.forEach(value => { - const opt = document.createElement('option'); - opt.value = value; - opt.textContent = value; - select.appendChild(opt); - }); - - return select; - } + if (selectRow && subjectName === name) { + selectRow.querySelector('.dropdown-cell').querySelector('.dropdown').value = gradeExam; + selectRadioButton(selectRow, gradeReport); + selectRow.querySelector('.unit-input').value = unit; + selectRow.querySelector('.subDropdown').value = subCategory; + selectRow.querySelector('.formDropdown').value = subForm; + } + } + function getIndex(examName, groupName) { + const parsedYear = parseInt(examName.slice(0,2))+2000; + const examNameLast = examName.slice(4); + const year = profile.value.year; + const month = profile.value.month; + let adj; + let term_check; + + if (month == 4 || month == '') { + const termMap = new Map([ + ['4月試験', 1], + ['7月試験', 2], + ['夏スク', 3], + ['10月試験', 4], + ['1月試験', 5], + ['秋スク', 6], + ]); + term_check = termMap.get(examNameLast) || 0; + adj = 0; + } else if (month == 10) { + const termMap = new Map([ + ['4月試験', 4], + ['7月試験', 5], + ['夏スク', 6], + ['10月試験', 1], + ['1月試験', 2], + ['秋スク', 3], + ]); + term_check = termMap.get(examNameLast) || 0; + adj = term_check < 3 ? 0 : 1; + } + const currentYear = parsedYear - year + 1 - adj; + const i = (currentYear - 1)*eventPerYear + term_check -1; + const groupMap = new Map([ + ['A群', 0], + ['B群', 1], + ['C群', 2], + ['D群', 3], + ['E群', 4], + ['F群', 5], + ]); + const j = groupMap.get(groupName) || 0; + return [i, j]; + } - function initPlanSheet() { - tableBody.innerHTML = ''; - for (let i = 0; i < rows; i++) { - const row = document.createElement('tr'); - const labelCell = document.createElement('td'); - const categoriesToFilter = depCategories; - const currentYear = Math.floor(i / reptRow); - const maxLevel = initLevel + (currentYear) * 2; - const GroupArray = ['A', 'B', 'C', 'D', 'E', 'F']; - const term_check = i % reptRow; - var term = ''; - var columnOptions; - - switch (term_check) { - case 0: - case 3: - columnOptions = [...optionsData.default, ...optionsData.text, ...optionsData.other]; - break; - case 1: - case 4: - if(i < 3){ - columnOptions = [...optionsData.default, ...optionsData.text, ...optionsData.other]; - }else{ - columnOptions = [...optionsData.default, ...optionsData.text, ...optionsData.media, ...optionsData.other]; - } - break; - case 2: - case 5: - columnOptions = [...optionsData.default, ...optionsData.school, ...optionsData.other]; - break; - } - - const yearValue = parseInt(year.value); - const parsedYear = isNaN(yearValue) ? 2000 : yearValue + currentYear; - - if (month.value == 4 || month.value == '') { - term = term_check < 3 ? 'A': 'B'; - adj = 0; - } else if (month.value == 10) { - term = term_check < 3 ? 'B': 'A'; - adj = term_check < 3 ? 0 : 1; - } - - const y = parsedYear + adj; - - if(i===0){ - console.log(term); - console.log(y); - } - - labelCell.id = `label-${i}`; - labelCell.textContent = termLabel[i]; - row.appendChild(labelCell); - - for (let j = 0; j < cols; j++) { - const filteredOptions = filterOptionsByCategories(columnOptions, categoriesToFilter, maxLevel, GroupArray[j], y, term); - const cell = document.createElement('td'); - const select = createDropdown(filteredOptions); - - select.id = `subject-${i}-${j}`; - select.addEventListener('change', updateSelectedValuesTable); - - cell.appendChild(select); - row.appendChild(cell); - } - - tableBody.appendChild(row); - } - updatePlanSheet(); - } + console.log(entries); + entries.forEach(entry => { + const [i, j] = getIndex(entry.examName, entry.groupName); + inputName(i, j, entry.name); + }); + refresh('byPlan'); + entries.forEach(entry => { + const [i, j] = getIndex(entry.examName, entry.groupName); + console.log(entry.name, entry.grade, entry.reportResult,entry.unitCount,entry.category,entry.form); + inputGrade(i, j, entry.name, entry.grade, entry.reportResult,entry.unitCount,entry.category,entry.form); + }); +}; - function updatePlanSheet(){ - updateTermLabel(); - if (isNaN(dispterm) || dispterm < 0 || dispterm > rows) return; - const tableRows = tableBody.getElementsByTagName('tr'); - for (let i = 0; i < rows; i++) { - tableRows[i].style.display = (i < dispterm) ? '' : 'none'; - } - tableRows[0].style.display = 'none'; - if(month.value == 10) { - tableRows[2].style.display = 'none'; //10月入学は1年目の秋スクを受けられない - } - } +function writeUnitTable() { + let result; + let headerText; + let commentText; + let footerText; + const unitsTexts = []; + const titleList = ['認定:', '人文:', '社会:', '科学:', '統計:', '必語:', '他語:', '保体:', '必修:', '選必:', '選択:', '卒論:']; + //getUnitsTable(); //更新してから書き出したい + for (i = 0; i < 12; i++) { + unitsTexts[i] = []; + for (j = 1; j < 4; j++) { + if(units[i][j-1] == 0) { + unitsTexts[i][j] = '--'; + } else if (units[i][j-1] < 10) { + unitsTexts[i][j] = '0' + units[i][j-1]; + } else { + unitsTexts[i][j] = units[i][j-1]; + } + } + unitsTexts[i][0] = titleList[i]; + unitsTexts[i][4] = '\n'; + } - function updateFilter() { - switch (courseSelect.value) { - case '普通課程': - initLevel = 2; - switch (departmentSelect.value) { - case '文学部': - depCategories = ["","A","F","L"]; - break; - case '経済学部': - depCategories = ["","A","F","E"]; - break; - case '法学部': - depCategories = ["","A","F","J"]; - break; - default: - depCategories = [""]; - break; - } - break; - case '特別課程': - initLevel = 4; - switch (departmentSelect.value) { - case '文学部': - depCategories = ["","A","F","L"]; - break; - case '経済学部': - depCategories = ["","A","F","E"]; - break; - case '法学部': - depCategories = ["","A","F","J"]; - break; - default: - depCategories = [""]; - break; - } - break; - case '学士入学': - initLevel = 5; - switch (departmentSelect.value) { - case '文学部': - depCategories = ["","F","L"]; - break; - case '経済学部': - depCategories = ["","F","E"]; - break; - case '法学部': - depCategories = ["","F","J"]; - break; - default: - depCategories = [""]; - break; - } - break; - default: - initLevel = 0; - depCategories = [""]; - break; - } - } + let commentBox = document.getElementById('commentText'); + commentText = commentBox.value; + if(commentText.length > 27) { commentText = ''; } + headerText = '慶應通信履修状況(学部:' + labels.dept + labels.sect + '/' + labels.course +')\n'; + footerText = 'コメント:' + commentText + '\n'; + result = unitsTexts.join(""); + result = result.replace(/:,/g, ":"); + result = result.replace(/認定:(\d{2}|--),(\d{2}|--),(\d{2}|--)/g, "認定:$1"); + result = result.replace(/保体:(\d{2}|--),(\d{2}|--),(\d{2}|--)/g, "保体:$1,$2"); + result = result.replace(/卒論:(\d{2}|--),(\d{2}|--),(\d{2}|--)/g, "卒論:$1"); + result = result.replace(/,\n/g, "\n"); + result = result.replace(/,/g, "/"); + result = headerText + '分類:T/S/M\n' + result + footerText; + let textarea = document.getElementById('textarea'); + textarea.value = result; +}; - - function createRadioButtons(rowId) { - const div = document.createElement('div'); - div.className = 'radio-group'; - const radioOptions = ['未', '合格', '失効']; - - radioOptions.forEach((value, index) => { - const label = document.createElement('label'); - const input = document.createElement('input'); - input.type = 'radio'; - input.name = `radio-group-${rowId}`; - input.value = value; - if (value === '合格') { - input.checked = true; // 「合格」を既定でチェック - } - label.appendChild(input); - label.appendChild(document.createTextNode(value)); - div.appendChild(label); - }); - - return div; - } +function readUnitTable() { + const inputText = document.getElementById('textarea').value; + const textLines = inputText.split('\n'); + const departmentId = $('#department'); + const sectionId = $('#section'); + const courseId = $('#course'); - function updateTotalUnit() { - const selectedRows = document.querySelectorAll('#selectedValuesBody tr'); - totalUnit = 0; - for (let i = 0; i < grades.length; i++) { - for (let j = 0; j < grades[i].length; j++) { - grades[i][j] = 0; - } - } - - - selectedRows.forEach(row => { - const radioChecked = row.querySelector('.radio-group input[type="radio"]:checked'); - const unitInput = row.querySelector('.unit-input'); - const dropdown = row.querySelector('.dropdown'); - const subDropdown = row.querySelector('.subDropdown'); - const formDropdown = row.querySelector('.formDropdown'); - - if ((dropdown.value !== '未' && dropdown.value !== 'D') && radioChecked && radioChecked.value === '合格') { - totalUnit += unitInput.valueAsNumber; - for(let i = 0; i < subCateOptions.length; i++) { - for (let j = 0; j < formOptions.length; j++) { - if (subDropdown.value === subCateOptions[i] && formDropdown.value === formOptions[j] ){ - grades[i+1][j] += unitInput.valueAsNumber; - if (i == 3) { - grades[i][j] += unitInput.valueAsNumber; - } - } - } - } - } - }) - document.getElementById('totalUnit').textContent = totalUnit; - updateForm(); - changeValue(); - } + // 更新処理の関数 + function updateDepartmentAndSection(line) { + if (line.includes('文')) { + departmentId.val('文学部'); + refresh('byDepartment'); + sectionId.val(line.includes('1') ? '第1類' : + line.includes('2') ? '第2類' : + line.includes('3') ? '第3類' : ''); + } else if (line.includes('経')) { + departmentId.val('経済学部'); + refresh('byDepartment'); + } else if (line.includes('法')) { + departmentId.val('法学部'); + refresh('byDepartment'); + sectionId.val(line.includes('法甲') ? '甲類' : + line.includes('法乙') ? '乙類' : ''); + } else { + departmentId.val('学部'); + } + } - function updateSelectedValuesTable() { - const selectedValuesBody = document.getElementById('selectedValuesBody'); - selectedValuesBody.innerHTML = ''; - const filterCriteria = ['----テキスト----', '----Eスク----', '--']; - let totalUnit = 0; - - for (let i = 0; i < rows; i++) { - for (let j = 0; j < cols; j++) { - const selectLabel = document.getElementById(`label-${i}`); - const selectedLabelVal = selectLabel.textContent; - const select = document.getElementById(`subject-${i}-${j}`); - const selectedValue = select.value; - const selectedOption = Array.from(select.options).find(opt => opt.value === selectedValue); - const shouldExclude = filterCriteria.some(criteria => selectedValue.includes(criteria)); - const GroupArray = ['A群', 'B群', 'C群', 'D群', 'E群', 'F群']; - const radioButtonsDiv = createRadioButtons(i*cols+j); - const row = document.createElement('tr'); - - const labelCell = document.createElement('td'); - //labelCell.textContent = selectedLabelVal + '-' + GroupArray[j]; - labelCell.textContent = selectedLabelVal; - row.appendChild(labelCell); - - const cell = document.createElement('td'); - cell.textContent = selectedValue; - row.appendChild(cell); - - const optionsCell1 = document.createElement('td'); - const gradeOptions = ['未', 'S', 'A', 'B', 'C', 'D']; - const dropdown = createDropdown2(gradeOptions); - dropdown.classList.add('dropdown'); // クラス名を設定 - optionsCell1.appendChild(dropdown); // Pass an empty array since we're using default options - optionsCell1.addEventListener('change', updateTotalUnit); - row.appendChild(optionsCell1); - - const optionsCell2 = document.createElement('td'); - optionsCell2.appendChild(radioButtonsDiv); - optionsCell2.addEventListener('change', updateTotalUnit); - row.appendChild(optionsCell2); - - const unitCell = document.createElement('td'); - const unitInput = document.createElement('input'); - unitInput.type = 'number'; - unitInput.min = 0; - unitInput.max = 8; - unitInput.value = selectedOption ? parseInt(selectedOption.dataset.unit, 10) : 0; - unitInput.classList.add('unit-input'); - unitInput.addEventListener('change', updateTotalUnit); - unitCell.appendChild(unitInput); - row.appendChild(unitCell); - - const subCateCell = document.createElement('td'); - const subcategories = JSON.parse(selectedOption.dataset.subcategory); - const subDropdown = createDropdown2(subcategories); - subDropdown.classList.add('subDropdown'); // クラス名を設定 - //subDropdown.value = selectedOption ? selectedOption.dataset.subcategory : 0; - subCateCell.appendChild(subDropdown); - subCateCell.addEventListener('change', updateTotalUnit); - row.appendChild(subCateCell); - - const formCell = document.createElement('td'); - const forms = JSON.parse(selectedOption.dataset.form); - const formDropdown = createDropdown2(forms); - formDropdown.classList.add('formDropdown'); // クラス名を設定 - formCell.appendChild(formDropdown); - formCell.addEventListener('change', updateTotalUnit); - row.appendChild(formCell); - - selectedValuesBody.appendChild(row); - - if (shouldExclude) { - row.classList.add('hidden'); - } - - const radioChecked = radioButtonsDiv.querySelector('input[type="radio"]:checked'); - if ((dropdown.value !== '未' && dropdown.value !== 'D') && radioChecked && radioChecked.value === '合格') { - totalUnit += unitInput.valueAsNumber; - } - - } - } - document.getElementById('totalUnit').textContent = totalUnit; - } + // コース更新処理の関数 + function updateCourse(line) { + courseId.val(line.includes('/普') ? '普通課程' : + line.includes('/特') ? '特別課程' : + line.includes('/学') ? '学士入学' : '入学課程'); + } - initPlanSheet(); - updateTermLabel(); - updateSections(); - updatePlanSheet(); - updateSelectedValuesTable(); - }); + // データの読み込み処理の関数 + function updateUnitsFromTexts(lines) { + lines.slice(3, 14).forEach((line, i) => { + const [key, values] = line.split(':'); + const data = values.replace(/--/g, "00").split('/').map(v => parseInt(v, 10)).map(v => (v<0 ||isNaN(v)) ? 0 : v); + switch (key) { + case '保体': + units[i + 1][0] = data[0]; + units[i + 1][1] = data[1]; + break; + case '卒論': + units[i + 1][0] = data[0]; + break; + default: + units[i + 1][0] = data[0]; + units[i + 1][1] = data[1]; + units[i + 1][2] = data[2]; + break; + } + }); + } + updateDepartmentAndSection(textLines[0]); + updateCourse(textLines[0]); + updateUnitsFromTexts(textLines); + + //ここは refresh 関数に任せる + //updateUnitsTable(); + //changeValue(); + refresh('byCourse'); +} -function writeGrades() { - let result; - let headerText; - let commentText; - let footerText; - const gradesTexts = []; - const titleList = ['認定:', '人文:', '社会:', '科学:', '統計:', '必語:', '他語:', '保体:', '必修:', '選必:', '選択:', '卒論:']; - getForm(); - for (i = 0; i < 12; i++) { - gradesTexts[i] = []; - for (j = 1; j < 4; j++) { - if(grades[i][j-1] == 0) { - gradesTexts[i][j] = '--'; - } else if (grades[i][j-1] < 10) { - gradesTexts[i][j] = '0' + grades[i][j-1]; +function initializeTables() { + function createInputTable() { + const inputTableRows = [ + { major: '総', minor: '認定', id: 'Apply', cols: ['', '', '', '']}, + { major: '', minor: '人文', id: 'Arts1', cols: [, , , ]}, + { major: '', minor: '社会', id: 'Arts2', cols: [, , , ]}, + { major: '', minor: '科学', id: 'Arts3', cols: [, , , ]}, + { major: '', minor: '統計', id: 'Stat', cols: [,,,'']}, + { major: '', minor: '必語', id: 'FL1', cols: [,,,'']}, + { major: '', minor: '他語', id: 'FL2', cols: [,,,'']}, + { major: '', minor: '保体', id: 'Sports', cols: [,,'', ''] }, + { major: '専', minor: '必修', id: 'Required', cols: [,,,'']}, + { major: '', minor: '選必', id: 'Elective1' , cols: [,,,'']}, + { major: '', minor: '選択', id: 'Elective2' , cols: [,,,'']}, + { major: '論', minor: '卒論', id: 'Thesis', cols: [,'','',''] } + ]; + + const tableBody = document.getElementById('inputTableBody'); + + inputTableRows.forEach(row => { + const tr = document.createElement('tr'); + + const majorTd = document.createElement('td'); + majorTd.classList.add('major'); + majorTd.textContent = row.major; + tr.appendChild(majorTd); + + const minorTd = document.createElement('td'); + minorTd.classList.add('minor'); + minorTd.textContent = row.minor; + tr.appendChild(minorTd); + + ['text', 'school', 'media', 'subjNum'].forEach((cls, idx) => { + const td = document.createElement('td'); + td.classList.add(cls); + if (row.cols && row.cols[idx] !== undefined) { + td.textContent = row.cols[idx]; + td.id = `${row.id}-${cls}`; } else { - gradesTexts[i][j] = grades[i][j-1]; + const input = document.createElement('input'); + input.type = 'number'; + input.size = 3; + input.id = `${row.id}-${cls}`; + input.value = 0; + input.min = 0; + input.max = cls === 'subjNum' ? 9 : 99; + td.appendChild(input); } - } - gradesTexts[i][0] = titleList[i]; - gradesTexts[i][4] = '\n'; + tr.appendChild(td); + }); + + tableBody.appendChild(tr); + }); + } + + function createSummaryTable() { + const tableBody = document.getElementById('gradeTableBody'); + Object.entries(decisions) + .filter(([key, value]) => value.id <= 15) // id が 15 以下のものだけフィルタリング + .forEach(([key, item]) => { + const tr = document.createElement('tr'); + const properties = ['major', 'minor', 'total', 'entry', 'approve', 'submit', 'graduate', 'prog']; + + properties.forEach(property => { + const td = document.createElement('td'); + td.classList.add(property); + td.id = `${key}-${property}`; + td.textContent = item[property] !== undefined ? item[property] : ''; // プロパティが存在する場合は値、存在しない場合は空欄 + tr.appendChild(td); + }); + + tableBody.appendChild(tr); + }); + } + + createInputTable(); + createSummaryTable(); +} + +function refresh(mode) { + var subjCategories = [""]; + + function checkSubcategory(subcategory) { + const language = profile.value.language; + const department = profile.value.department; + const section = profile.value.section; + let result = []; + const categoryMap = { + 'any': ['人文', '社会', '科学', '統計', '必語', '他語', '保体', '必修', '選必', '選択', '自由'], + '人文': [subcategory], + '社会': [subcategory], + '科学': [subcategory], + '統計': [subcategory], + '他語': [subcategory], + '保体': [subcategory], + '必修': [subcategory], + '選必': [subcategory], + '選択': [subcategory], + '英': [language === '英語' ? '必語' : '他語'], + '独': [language === 'ドイツ語' ? '必語' : '他語'], + '仏': [language === 'フランス語' ? '必語' : '他語'], + '1類': [section === '第1類' ? '必修' : '選択'], + '2類': [section === '第2類' ? '必修' : '選択'], + '3類': [section === '第3類' ? '必修' : '選択'], + '共通': [department === '文学部' ? '必修' : '選択'] + }; + result = categoryMap[subcategory] || []; + return JSON.stringify(result); + } + + // Profile が変更された時の更新処理 + function updateProfile (mode) { + const sections = { + '文学部': ['第1類', '第2類', '第3類'], + '経済学部': [''], + '法学部': ['甲類', '乙類'], + }; + const dept = document.getElementById('department').value; + const sects = sections[dept] || []; + const html = sects.map(function(sct) { + return ''; + }).join(''); + if (mode === 'byDepartment'){ + profile.Element1.section.innerHTML = html; + profile.Element2.section.innerHTML = html; } - let commentbox = document.getElementById('commentText'); - commentText = commentbox.value; - if(commentText.length > 27) { commentText = ''; } - - headerText = '慶應通信履修状況(学部:' + deptLabel + sectLabel + '/' + courseLabel +')\n'; - footerText = 'コメント:' + commentText + '\n'; - result = gradesTexts.join(""); - result = result.replace(/:,/g, ":"); - result = result.replace(/認定:(\d{2}|--),(\d{2}|--),(\d{2}|--)/g, "認定:$1"); - result = result.replace(/保体:(\d{2}|--),(\d{2}|--),(\d{2}|--)/g, "保体:$1,$2"); - result = result.replace(/卒論:(\d{2}|--),(\d{2}|--),(\d{2}|--)/g, "卒論:$1"); - result = result.replace(/,\n/g, "\n"); - result = result.replace(/,/g, "/"); - result = headerText + '分類:T/S/M\n' + result + footerText; - let textarea = document.getElementById('textarea'); - textarea.value = result; -}; + const applyStat = document.getElementById('apply_stat').checked ? 4 : null; + const applyFl1 = document.getElementById('apply_fl1').checked ? 8 : null; -function readGrades() { - const inputText = document.getElementById('textarea').value; - const textline = inputText.split('\n'); - const departmentid = $('#department'); - const sectionid = $('#section'); - const courseid = $('#course'); - - if (textline[0].includes('文')) { - departmentid.val('文学部'); - updateSections(); - if (textline[0].includes('1')) { - sectionid.val('第1類'); - } else if (textline[0].includes('2')) { - sectionid.val('第2類'); - } else if (textline[0].includes('3')) { - sectionid.val('第3類'); + if (applyStat !== null){ + $('#stat-text').val(applyStat); + units[4][0] = applyStat; } - } else if (textline[0].includes('経')) { - departmentid.val('経済学部'); - updateSections(); - } else if (textline[0].includes('法')) { - departmentid.val('法学部'); - updateSections(); - if (textline[0].includes('法甲')) { - sectionid.val('甲類'); - }else if (textline[0].includes('法乙')) { - sectionid.val('乙類'); - } - } else { - departmentid.val('学部') + if (applyFl1 !== null){ + $('#fl1-text').val(applyFl1); + units[5][0] = applyFl1; + } + + const selectSect = $('#section option:selected').val() || ''; + const departmentConfig = { + '文学部': {deptLabel: '文', sectLabel: selectSect.charAt(1) }, + '経済学部': {deptLabel: '経', sectLabel: '' }, + '法学部': {deptLabel: '法', sectLabel: selectSect.charAt(0) } + }; + const selectedDept = $('#department option:selected').val(); + const deptConfig = departmentConfig[selectedDept] || {deptLabel: '-', sectLabel: '' }; + + const courseConfig = { + '普通課程': {applyText: 0, courseLabel: '普' }, + '特別課程': {applyText: 18, courseLabel: '特' }, + '学士入学': { + applyText: (dept === '経済学部' && !document.getElementById('apply_stat').checked) ? 36 : 40, + courseLabel: '学' + } + }; + + const selectedCourse = $('#course option:selected').val(); + const crsConfig = courseConfig[selectedCourse] || {applyText: 0, courseLabel: '-' }; + + labels.dept = deptConfig.deptLabel; + labels.sect = deptConfig.sectLabel; + labels.course = crsConfig.courseLabel; + units[0][0] = crsConfig.applyText; } - if (textline[0].includes('/普')) { - courseid.val('普通課程'); - } else if (textline[0].includes('/特')){ - courseid.val('特別課程'); - } else if (textline[0].includes('/学')){ - courseid.val('学士入学'); - } else { - courseid.val('入学課程'); + + function getProfile(){ + profile.value.year = document.getElementById('year').value; + profile.value.month = document.getElementById('month').value; + profile.value.department = document.getElementById('department').value; + profile.value.section = document.getElementById('section').value; + profile.value.course = document.getElementById('course').value; + profile.value.language = document.getElementById('language').value; + profile.value.stat = document.getElementById('apply_stat').checked; + profile.value.appLang = document.getElementById('apply_fl1').checked; + profile.value.years = document.getElementById('years').value; + profile.value.months = document.getElementById('months').value; } - for (i = 3; i < 14; i++) { - const str1 = textline[i].split(':'); - const str2 = str1[1].replace(/--/g, "00").split('/'); - switch (str1[0]) { - case '保体': - for (j =0; j < 2; j++) { - grades[i-2][j] = parseInt(str2[j]); - } - break; - case '卒論': - for (j =0; j < 1; j++) { - grades[i-2][j] = parseInt(str2[j]); - } - break; - default: - for (j =0; j < 3; j++) { - grades[i-2][j] = parseInt(str2[j]); - } - break; + // 実績表のプルダウンが変更された時に合計単位数を計算、表示する処理 + function updateTotalUnit() { + const selectedRows = document.querySelectorAll('#ActualBody tr'); + const applyText = units[0][0]; + const applyStat = document.getElementById('apply_stat').checked ? 4 : null; + const applyFl1 = document.getElementById('apply_fl1').checked ? 8 : null; + totalUnit = 0; + + for (let i = 0; i < units.length; i++) { + for (let j = 0; j < units[i].length; j++) { + if(i === 0 && j === 0){ + units[i][j] = applyText; + }else if(i === 4 && j === 0 && applyStat !== null){ + units[i][j] = applyStat; + } else if(i === 5 && j === 0 && applyFl1 !== null){ + units[i][j] = applyFl1; + } else { + units[i][j] = 0; + } } - } - updateForm(); - changeValue(); -} + } -function getForm(){ - grades[1][0] = parseInt(document.getElementById('arts1-text').value); - grades[1][1] = parseInt(document.getElementById('arts1-school').value); - grades[1][2] = parseInt(document.getElementById('arts1-media').value); - grades[2][0] = parseInt(document.getElementById('arts2-text').value); - grades[2][1] = parseInt(document.getElementById('arts2-school').value); - grades[2][2] = parseInt(document.getElementById('arts2-media').value); - grades[3][0] = parseInt(document.getElementById('arts3-text').value); - grades[3][1] = parseInt(document.getElementById('arts3-school').value); - grades[3][2] = parseInt(document.getElementById('arts3-media').value); - grades[4][0] = parseInt(document.getElementById('stat-text').value); - grades[4][1] = parseInt(document.getElementById('stat-school').value); - grades[4][2] = parseInt(document.getElementById('stat-media').value); - grades[5][0] = parseInt(document.getElementById('fl1-text').value); - grades[5][1] = parseInt(document.getElementById('fl1-school').value); - grades[5][2] = parseInt(document.getElementById('fl1-broad').value); - grades[6][0] = parseInt(document.getElementById('fl2-text').value); - grades[6][1] = parseInt(document.getElementById('fl2-school').value); - grades[6][2] = parseInt(document.getElementById('fl2-broad').value); - grades[7][0] = parseInt(document.getElementById('sports-text').value); - grades[7][1] = parseInt(document.getElementById('sports-school').value); - grades[8][0] = parseInt(document.getElementById('required-text').value); - grades[8][1] = parseInt(document.getElementById('required-school').value); - grades[8][2] = parseInt(document.getElementById('required-media').value); - grades[9][0] = parseInt(document.getElementById('elective1-text').value); - grades[9][1] = parseInt(document.getElementById('elective1-school').value); - grades[9][2] = parseInt(document.getElementById('elective1-media').value); - grades[10][0] = parseInt(document.getElementById('elective2-text').value); - grades[10][1] = parseInt(document.getElementById('elective2-school').value); - grades[10][2] = parseInt(document.getElementById('elective2-media').value); - grades[11][0] = parseInt(document.getElementById('thesis-total').value); - subjNum[1] = parseInt(document.getElementById('arts1-subjNum').value); - subjNum[2] = parseInt(document.getElementById('arts2-subjNum').value); - subjNum[3] = parseInt(document.getElementById('arts3-subjNum').value); -} + selectedRows.forEach(row => { + const formOptions = ['T', 'S', 'M/B']; + const subCateOptions = ['人文', '社会', '科学', '統計', '必語', '他語', '保体', '必修', '選必', '選択']; + const radioChecked = row.querySelector('.radio-group input[type="radio"]:checked'); + const unitInput = row.querySelector('.unit-input'); + const dropdown = row.querySelector('.dropdown'); + const subDropdown = row.querySelector('.subDropdown'); + const formDropdown = row.querySelector('.formDropdown'); + + if (dropdown.value !== '未' && dropdown.value !== 'D' && radioChecked?.value === '合格') { + const unitValue = unitInput.valueAsNumber; + totalUnit += unitValue; + + const subIndex = subCateOptions.indexOf(subDropdown.value); + const formIndex = formOptions.indexOf(formDropdown.value); + + if (subIndex !== -1 && formIndex !== -1) { + units[subIndex + 1][formIndex] += unitValue; + if (subIndex === 3) { + units[subIndex][formIndex] += unitValue; + } + } + } + }); + document.getElementById('totalUnit').textContent = totalUnit; + //updateForm(); + } + + function getUnitsTable() { + elements.forEach(({ prefix, index }) => { + units[index][0] = parseInt(document.getElementById(`${prefix}-text`).value) || 0; + units[index][1] = parseInt(document.getElementById(`${prefix}-school`).value) || 0; + units[index][2] = parseInt(document.getElementById(`${prefix}-media`).value) || 0; + }); + + [1, 2, 3].forEach(i => { + subjNum[i] = parseInt(document.getElementById(`Arts${i}-subjNum`).value) || 0; + }); + } -function updateForm(){ - document.getElementById('arts1-text').value = grades[1][0]; - document.getElementById('arts1-school').value = grades[1][1]; - document.getElementById('arts1-media').value = grades[1][2]; - document.getElementById('arts2-text').value = grades[2][0]; - document.getElementById('arts2-school').value = grades[2][1]; - document.getElementById('arts2-media').value = grades[2][2]; - document.getElementById('arts3-text').value = grades[3][0]; - document.getElementById('arts3-school').value = grades[3][1]; - document.getElementById('arts3-media').value = grades[3][2]; - document.getElementById('stat-text').value = grades[4][0]; - document.getElementById('stat-school').value = grades[4][1]; - document.getElementById('stat-media').value = grades[4][2]; - document.getElementById('fl1-text').value = grades[5][0]; - document.getElementById('fl1-school').value = grades[5][1]; - document.getElementById('fl1-broad').value = grades[5][2]; - document.getElementById('fl2-text').value = grades[6][0]; - document.getElementById('fl2-school').value = grades[6][1]; - document.getElementById('fl2-broad').value = grades[6][2]; - document.getElementById('sports-text').value = grades[7][0]; - document.getElementById('sports-school').value = grades[7][1]; - document.getElementById('required-text').value = grades[8][0]; - document.getElementById('required-school').value = grades[8][1]; - document.getElementById('required-media').value = grades[8][2]; - document.getElementById('elective1-text').value = grades[9][0]; - document.getElementById('elective1-school').value = grades[9][1]; - document.getElementById('elective1-media').value = grades[9][2]; - document.getElementById('elective2-text').value = grades[10][0]; - document.getElementById('elective2-school').value = grades[10][1]; - document.getElementById('elective2-media').value = grades[10][2]; - document.getElementById('thesis-total').value = grades[11][0]; - document.getElementById('arts1-subjNum').value = subjNum[1]; - document.getElementById('arts2-subjNum').value = subjNum[2]; - document.getElementById('arts3-subjNum').value = subjNum[3]; -} + function setUnitsTable() { + elements.forEach(({ prefix, index }) => { + document.getElementById(`${prefix}-text`).value = units[index][0]; + document.getElementById(`${prefix}-school`).value = units[index][1]; + document.getElementById(`${prefix}-media`).value = units[index][2]; + + if (prefix.startsWith('Arts')) { + document.getElementById(`${prefix}-subjNum`).value = subjNum[index]; + } + }); + } -function updateTermLabel(){ - const year = document.getElementById('year'); - const month = document.getElementById('month'); - yearInd = isNaN(parseInt(year.value)) ? 1 : parseInt(year.value) % 100; - if (isNaN(parseInt(year.value))){ - if (month.value == 4 || month.value == '') { - for (let i = 0; i < 21; i++) { - termLabel[i*6] = String(yearInd + i) + '年目4月試験'; - termLabel[i*6+1] = String(yearInd + i) + '年目7月試験'; - termLabel[i*6+2] = String(yearInd + i) + '年目夏スク'; - termLabel[i*6+3] = String(yearInd + i) + '年目10月試験'; - termLabel[i*6+4] = String(yearInd + i) + '年目1月試験'; - termLabel[i*6+5] = String(yearInd + i) + '年目秋スク'; + function initPlanningTable(mode) { + function updateSubcategories() { + // 未実装 + } + function filterOptionsByCategories(options, categories, maxLevel, group, year, term) { + function filterTerms(year, term, pattern) { + const isOdd = parseInt(year) % 2 === 1; + switch (pattern) { + case 'Both': + return true; + case 'A': + return term === 'A'; + case 'B': + return term === 'B'; + case 'OddA': + return (isOdd && term === 'A') || (!isOdd && term === 'B'); + case 'OddB': + return (isOdd && term === 'B') || (!isOdd && term === 'A'); + default: + return false; + } + } + function filterSchedule(year, term, group, schedule) { + const Now = 2024; + if (year < 2019 || year > Now || !Array.isArray(schedule)) { + return false; + } + const foundItem = schedule.find(item => + Array.isArray(item) && item.length >= 3 && item[0] === year && item[1] === term && item[2] === group + ); + return foundItem ? true : false; } - } else if (month.value == 10) { - for (let i = 0; i < 21; i++) { - termLabel[i*6] = String(yearInd + i) + '年目10月試験'; - termLabel[i*6+1] = String(yearInd + i) + '年目1月試験'; - termLabel[i*6+2] = String(yearInd + i) + '年目秋スク'; - termLabel[i*6+3] = String(yearInd + i) + '年目4月試験'; - termLabel[i*6+4] = String(yearInd + i) + '年目7月試験'; - termLabel[i*6+5] = String(yearInd + i) + '年目夏スク'; + + return options.filter(option => + option.category.some(cat => categories.includes(cat)) && + option.level <= maxLevel && + (option.group ? option.group === group || option.group === '' : true) && + (option.start ? option.start <= year && option.end >= year : true) && + (option.pattern ? filterTerms(year, term, option.pattern): true) && + (option.schedule ? filterSchedule(year, term, group, option.schedule): true) && + (option.filter ? option.filter(categories, year, term) : true)&& + (option.COVID19filter ? option.COVID19filter(year, term, group) : true) + ); + } + + function createDropdown(options) { + function checkForm(form){ + let result = []; + switch (form) { + case 'any': + result = ['T', 'S', 'M/B']; + break; + default: + result[0] = form; + break; + } + return JSON.stringify(result); } + + const select = document.createElement('select'); + options.forEach(option => { + const opt = document.createElement('option'); + const section = profile.value.section + opt.value = option.value; + opt.textContent = option.value; + opt.dataset.unit = option.unit; + //opt.dataset.subcategories = JSON.stringify(option.subcategory); + let subCat; + if (Array.isArray(option.subcategory)) { + subCat = section === '甲類' ? option.subcategory[0] : option.subcategory[1]; + opt.dataset.subcategoriesA = option.subcategory[0]; + opt.dataset.subcategoriesB = option.subcategory[1]; + } else { + subCat = option.subcategory; + opt.dataset.subcategories = option.subcategory; + } + opt.dataset.subcategory = checkSubcategory(subCat); + opt.dataset.form = checkForm(option.form); + select.appendChild(opt); + }); + return select; } - } else { - if (month.value == 4 || month.value == '') { - for (let i = 0; i < 21; i++) { - termLabel[i*6] = String(yearInd + i) + '年度4月試験'; - termLabel[i*6+1] = String(yearInd + i) + '年度7月試験'; - termLabel[i*6+2] = String(yearInd + i) + '年度夏スク'; - termLabel[i*6+3] = String(yearInd + i) + '年度10月試験'; - termLabel[i*6+4] = String(yearInd + i) + '年度1月試験'; - termLabel[i*6+5] = String(yearInd + i) + '年度秋スク'; + + function getSubjCategories() { + const dept = profile.value.department; + const crs = profile.value.course; + const categories = { + '文学部': ["", "A", "F", "L"], + '経済学部': ["", "A", "F", "E"], + '法学部': ["", "A", "F", "J"], + '学部': [""] + }; + if(dept){ + subjCategories = (crs === '学士入学') + ? categories[dept].filter(cat => cat !== 'A') + : categories[dept]; + } + if (!subjCategories) { + subjCategories = categories['学部']; } - } else if (month.value == 10) { + return subjCategories; + } + + if(mode === 'init'){ + const tableBody = document.querySelector('#PlanningTable tbody'); + tableBody.innerHTML = ''; + for (let i = 0; i < PlanningRows; i++) { + const crs = profile.value.course; + const levels = { + '普通課程': 2, + '特別課程': 4, + '学士入学': 5 + }; + const initLevel = levels[crs] || 0; + const row = document.createElement('tr'); + const labelCell = document.createElement('td'); + const categoriesToFilter = getSubjCategories(); + const currentYear = Math.floor(i / eventPerYear); + const maxLevel = initLevel + (currentYear) * 2; + const GroupArray = ['A', 'B', 'C', 'D', 'E', 'F']; + const term_check = i % eventPerYear; + var term = ''; + var columnOptions; + + switch (term_check % 3) { + case 0: + columnOptions = [...optionsData.text, ...optionsData.other]; + break; + case 1: + columnOptions = i < 3 ? [...optionsData.text, ...optionsData.other]:[...optionsData.text, ...optionsData.media, ...optionsData.other]; + break; + case 2: + columnOptions = [...optionsData.school, ...optionsData.other]; + break; + } + + const yearValue = parseInt(profile.value.year); + const month = profile.value.month; + const parsedYear = isNaN(yearValue) ? 2000 : yearValue + currentYear; + + if (month == 4 || month == '') { + term = term_check < 3 ? 'A': 'B'; + adj = 0; + } else if (month == 10) { + term = term_check < 3 ? 'B': 'A'; + adj = term_check < 3 ? 0 : 1; + } + + const y = parsedYear + adj; + + labelCell.id = `label-${i}`; + row.appendChild(labelCell); + + for (let j = 0; j < groups; j++) { + const filteredOptions = filterOptionsByCategories(columnOptions, categoriesToFilter, maxLevel, GroupArray[j], y, term); + const cell = document.createElement('td'); + const select = createDropdown(filteredOptions); + + select.id = `subject-${i}-${j}`; + select.addEventListener('change', () => refresh('byPlan')); + + cell.appendChild(select); + row.appendChild(cell); + } + + tableBody.appendChild(row); + } + } else if (mode === 'update'){ + updateSubcategories(); + } + } + + // InputForm が変更された時の PlanningTable 表示範囲の更新処理 + function updatePlanningTable(){ + const years = profile.value.years; + const months = profile.value.months; + const displayTerm = parseInt(years * 2 + months/6)*3; + const tableBody = document.querySelector('#PlanningTable tbody'); + + // PlanningTable の時間ラベルを変更する関数 + function updateTermLabel() { + const year = profile.value.year; + const month = profile.value.month; + const yearInd = isNaN(parseInt(year)) ? 1 : parseInt(year) % 100; + const termLabels = [ + '4月試験', '7月試験', '夏スク', '10月試験', '1月試験', '秋スク' + ]; + var termLabel = []; + + // 月によるラベルの順序設定 + const order = month == 10 + ? [3, 4, 5, 0, 1, 2] + : [0, 1, 2, 3, 4, 5]; + for (let i = 0; i < 21; i++) { - termLabel[i*6] = String(yearInd + i) + '年度10月試験'; - termLabel[i*6+1] = String(yearInd + i) + '年度1月試験'; - termLabel[i*6+2] = String(yearInd + i) + '年度秋スク'; - termLabel[i*6+3] = String(yearInd + i +1) + '年度4月試験'; - termLabel[i*6+4] = String(yearInd + i +1) + '年度7月試験'; - termLabel[i*6+5] = String(yearInd + i +1) + '年度夏スク'; + termLabels.forEach((label, idx) => { + const yearSuffix = isNaN(parseInt(year)) ? (yearInd + i) : (yearInd + i + (month == 10 ? 1 : 0)); + termLabel[i * 6 + idx] = `${yearSuffix}年度${termLabels[order[idx]]}`; + }); + } + + // ラベル要素の更新 + for (let i = 0; i < PlanningRows; i++) { + const labelId = `label-${i}`; + const labelEle = document.getElementById(labelId); + if (labelEle) { + labelEle.textContent = termLabel[i]; + } } } + + updateTermLabel(); + if (isNaN(displayTerm) || displayTerm < 0 || displayTerm > PlanningRows) return; + const tableRows = tableBody.getElementsByTagName('tr'); + for (let i = 0; i < PlanningRows; i++) { + tableRows[i].style.display = (i < displayTerm) ? '' : 'none'; + } + tableRows[0].style.display = 'none'; + if(month.value == 10) { + tableRows[2].style.display = 'none'; //10月入学は1年目の秋スクを受けられない + } + } + + function updateActualTable() { + function createRadioButtons(rowId) { + const div = document.createElement('div'); + div.className = 'radio-group'; + const radioOptions = ['未', '合格', '失効']; + + radioOptions.forEach((value, index) => { + const label = document.createElement('label'); + const input = document.createElement('input'); + input.type = 'radio'; + input.name = `radio-group-${rowId}`; + input.value = value; + if (value === '合格') { + input.checked = true; // 「合格」を既定でチェック + } + label.appendChild(input); + label.appendChild(document.createTextNode(value)); + div.appendChild(label); + }); + return div; + } + + const ActualBody = document.getElementById('ActualBody'); + ActualBody.innerHTML = ''; + const filterCriteria = ['--']; + let totalUnit = 0; + + for (let i = 0; i < PlanningRows; i++) { + for (let j = 0; j < groups; j++) { + function createDropdown2(options) { + if(!Array.isArray(options)) {return}; + //console.log(options); + const select = document.createElement('select'); + options.forEach(value => { + const opt = document.createElement('option'); + opt.value = value; + opt.textContent = value; + select.appendChild(opt); + }); + return select; + } + + function createInput(type, min, max, value, className, eventListener) { + const input = document.createElement('input'); + input.type = type; + if (min !== undefined) input.min = min; + if (max !== undefined) input.max = max; + input.value = value; + if (className) input.classList.add(className); + if (eventListener) input.addEventListener('change', eventListener); + return input; + } + + function createTableCell(content, className = '') { + const cell = document.createElement('td'); + if (content instanceof Node) { + cell.appendChild(content); + } else { + cell.textContent = content; + } + if (className) cell.classList.add(className); + return cell; + } + + const selectLabel = document.getElementById(`label-${i}`); + const selectedLabelVal = selectLabel ? selectLabel.textContent : null; + const select = document.getElementById(`subject-${i}-${j}`); + const selectedValue = select ? select.value : null; + if (!selectedLabelVal || !selectedValue) return; + + const selectedOption = Array.from(select.options).find(opt => opt.value === selectedValue); + const shouldExclude = filterCriteria.some(criteria => selectedValue.includes(criteria)); + const radioButtonsDiv = createRadioButtons(i * groups + j); + + const rowId = `actual-${i}-${j}` + const row = document.createElement('tr'); + row.id = rowId; + //console.log(row.id); + row.appendChild(createTableCell(selectedLabelVal, 'examName')); + row.appendChild(createTableCell(selectedValue, 'subjectName')); + + const gradeOptions = ['未', 'S', 'A', 'B', 'C', 'D']; + const dropdown = createDropdown2(gradeOptions); + dropdown.classList.add('dropdown'); + const optionsCell1 = createTableCell(dropdown, 'dropdown-cell'); + optionsCell1.addEventListener('change', () => refresh('byActual')); + row.appendChild(optionsCell1); + + const optionsCell2 = createTableCell(radioButtonsDiv, 'radio-buttons-cell'); + optionsCell2.addEventListener('change', () => refresh('byActual')); + row.appendChild(optionsCell2); + + const unitInput = createInput('number', 0, 8, selectedOption ? parseInt(selectedOption.dataset.unit, 10) : 0, 'unit-input', () => refresh('byActual')); + const unitCell = createTableCell(unitInput); + row.appendChild(unitCell); + //console.log(selectedOption.dataset.subcategories,selectedOption.dataset.subcategoriesA,selectedOption.dataset.subcategoriesB); + + function getSubCategories(dataset){ + switch (profile.value.section) { + case '甲類': + result = dataset.subcategoriesA ? checkSubcategory(dataset.subcategoriesA):checkSubcategory(dataset.subcategories); + break; + case '乙類': + result = dataset.subcategoriesB ? checkSubcategory(dataset.subcategoriesB):checkSubcategory(dataset.subcategories); break; + default: + result = checkSubcategory(dataset.subcategories); + break; + } + return JSON.parse(result); + } + const subcategories = getSubCategories(selectedOption.dataset); + const subDropdown = createDropdown2(subcategories); + subDropdown.classList.add('subDropdown'); + const subCateCell = createTableCell(subDropdown); + subCateCell.addEventListener('change', () => refresh('byActual')); + row.appendChild(subCateCell); + + const forms = JSON.parse(selectedOption.dataset.form); + const formDropdown = createDropdown2(forms); + formDropdown.classList.add('formDropdown'); + const formCell = createTableCell(formDropdown); + formCell.addEventListener('change', () => refresh('byActual')); + row.appendChild(formCell); + + ActualBody.appendChild(row); + + if (shouldExclude) row.classList.add('hidden'); + + const radioChecked = radioButtonsDiv.querySelector('input[type="radio"]:checked'); + if ((dropdown.value !== '未' && dropdown.value !== 'D') && radioChecked && radioChecked.value === '合格') { + totalUnit += unitInput.valueAsNumber; + } + } + } + + document.getElementById('totalUnit').textContent = totalUnit; + + } + + const actions = { + byProfile: [ + () => updateProfile('byOther'), + getProfile, + updatePlanningTable, + updateActualTable, + updateTotalUnit, + showCharts, + setUnitsTable + ], + byDepartment: [ + () => updateProfile('byDepartment'), + getProfile, + () => initPlanningTable('init'), + updatePlanningTable, + updateActualTable, + updateTotalUnit, + showCharts, + setUnitsTable + ], + bySect: [ + getProfile, + //() => initPlanningTable('init'), + updatePlanningTable, + updateActualTable, + updateTotalUnit, + showCharts, + setUnitsTable + ], + byLang: [ + () => updateProfile('byOther'), + getProfile, + //() => initPlanningTable('init'), + updatePlanningTable, + updateActualTable, + updateTotalUnit, + showCharts, + setUnitsTable + ], + byCourse: [ + () => updateProfile('byCourse'), + getProfile, + () => initPlanningTable('init'), + updatePlanningTable, + updateActualTable, + updateTotalUnit, + showCharts, + setUnitsTable + ], + byPlan: [ + updateActualTable + ], + byActual: [ + updateTotalUnit, + showCharts, + setUnitsTable + ], + byTable: [ + getUnitsTable, + showCharts + ], + }; + const functionsToRun = actions[mode] || []; + functionsToRun.forEach(func => func()); +} + +function setupEventListeners() { + function setProfile(){ + profile.Element1.year = document.getElementById('year_1'); + profile.Element1.month = document.getElementById('month_1'); + profile.Element1.department = document.getElementById('department_1'); + profile.Element1.section = document.getElementById('section_1'); + profile.Element1.course = document.getElementById('course_1'); + profile.Element1.language = document.getElementById('language_1'); + profile.Element1.stat = document.getElementById('apply_stat_1'); + profile.Element1.appLang = document.getElementById('apply_fl1_1'); + profile.Element2.year = document.getElementById('year'); + profile.Element2.month = document.getElementById('month'); + profile.Element2.department = document.getElementById('department'); + profile.Element2.section = document.getElementById('section'); + profile.Element2.course = document.getElementById('course'); + profile.Element2.language = document.getElementById('language'); + profile.Element2.stat = document.getElementById('apply_stat'); + profile.Element2.appLang = document.getElementById('apply_fl1'); + profile.Element2.years = document.getElementById('years'); + profile.Element2.months = document.getElementById('months'); } - for (let i = 0; i < rows; i++) { - const labelId = `label-${i}`; - const labelEle = document.getElementById(labelId); - if (labelEle) { - labelEle.textContent = termLabel[i]; + + function createSyncs() { + function syncInputs(input1, input2, eventType) { + input1.addEventListener(eventType, function() { + input2.value = input1.value; + }); + input2.addEventListener(eventType, function() { + input1.value = input2.value; + }); } + function syncCheckboxes(checkbox1, checkbox2) { + checkbox1.addEventListener('change', function() { + checkbox2.checked = checkbox1.checked; + }); + checkbox2.addEventListener('change', function() { + checkbox1.checked = checkbox2.checked; + }); + } + syncInputs(profile.Element1.year, profile.Element2.year, 'input'); + syncInputs(profile.Element1.month, profile.Element2.month, 'change'); + syncInputs(profile.Element1.department, profile.Element2.department, 'change'); + syncInputs(profile.Element1.section, profile.Element2.section, 'change'); + syncInputs(profile.Element1.course, profile.Element2.course, 'change'); + syncInputs(profile.Element1.language, profile.Element2.language, 'change'); + syncCheckboxes(profile.Element1.stat, profile.Element2.stat); + syncCheckboxes(profile.Element1.appLang, profile.Element2.appLang); } + + function setListenersToProfile() { + profile.Element1.year.addEventListener('change', () => refresh('byProfile')); + profile.Element1.month.addEventListener('change', () => refresh('byProfile')); + profile.Element1.department.addEventListener('change', () => refresh('byDepartment')); + profile.Element1.section.addEventListener('change', () => refresh('bySect')); + profile.Element1.course.addEventListener('change', () => refresh('byCourse')); + profile.Element1.language.addEventListener('change', () => refresh('byLang')); + profile.Element1.stat.addEventListener('change', () => refresh('byProfile')); + profile.Element1.appLang.addEventListener('change', () => refresh('byProfile')); + profile.Element2.year.addEventListener('change', () => refresh('byProfile')); + profile.Element2.month.addEventListener('change', () => refresh('byProfile')); + profile.Element2.department.addEventListener('change', () => refresh('byDepartment')); + profile.Element2.section.addEventListener('change', () => refresh('bySect')); + profile.Element2.course.addEventListener('change', () => refresh('byCourse')); + profile.Element2.language.addEventListener('change', () => refresh('byLang')); + profile.Element2.stat.addEventListener('change', () => refresh('byProfile')); + profile.Element2.appLang.addEventListener('change', () => refresh('byProfile')); + profile.Element2.years.addEventListener('change', () => refresh('byProfile')); + profile.Element2.months.addEventListener('change', () => refresh('byProfile')); + } + + function setListenersToTable() { + elements.forEach(({ prefix, index }) => { + document.getElementById(`${prefix}-text`).addEventListener('change', () => refresh('byTable')); + document.getElementById(`${prefix}-school`).addEventListener('change', () => refresh('byTable')); + document.getElementById(`${prefix}-media`).addEventListener('change', () => refresh('byTable')); + }); + + [1, 2, 3].forEach(i => { + document.getElementById(`Arts${i}-subjNum`).addEventListener('change', () => refresh('byTable')); + }); + } + function handleFileSelect(event) { + const file = event.target.files[0]; + if (!file) return; + + const reader = new FileReader(); + reader.onload = function(e) { + const csvData = e.target.result; + entries = parseCSV(csvData); + console.log(entries); + }; + reader.readAsText(file); + } + // CSVデータのパースとマッピング処理 + function parseCSV(csvContent) { + const headerMap = { + '受講時期': 'examName', + '群': 'groupName', + '科目名': 'name', + '評価': 'grade', + 'レポ合否': 'reportResult', + '単位数': 'unitCount', + '区分': 'category', + '形態': 'form' + }; + const lines = csvContent.split('\n'); + const headers = lines[0].split(','); // ヘッダー行を取得 + const data = lines.slice(1); // ヘッダー以外のデータ行を取得 + + return data.map(line => { + const values = line.split(/,(?=(?:[^"]*"[^"]*")*[^"]*$)/).map(value => value.replace(/^"(.*)"$/, '$1').trim()); + const entry = {}; + headers.forEach((header, index) => { + const mappedKey = headerMap[header]; + if (mappedKey) { + entry[mappedKey] = values[index]; + } + }); + return entry; + }); + } + + document.getElementById('csvFileInput').addEventListener('change', handleFileSelect); + document.getElementById('csvFileInput2').addEventListener('change', handleFileSelect); + setProfile(); + createSyncs(); + setListenersToProfile(); + setListenersToTable(); } \ No newline at end of file diff --git a/docs/subjects.js b/docs/subjects.js index a2086a5..b68dc46 100644 --- a/docs/subjects.js +++ b/docs/subjects.js @@ -1,6 +1,4 @@ const optionsData = { - default: [ - ], text: [ { value: '----テキスト----', group: '', category: [''], subcategory: '', form: 'T', level: 0, unit: 0, start: 2000, end: 2100 }, { value: '哲学', group: 'E', category: ['A'], subcategory: '人文', form: 'T', level: 3, unit: 4, start: 2000, end: 2100 }, diff --git a/docs/update.js b/docs/update.js index 8723629..c4f634d 100644 --- a/docs/update.js +++ b/docs/update.js @@ -1,561 +1,453 @@ -var apply_total = 0; -var arts1_total = 0; -var arts2_total = 0; -var arts3_total = 0; -var arts1_SubjN = 0; -var arts2_SubjN = 0; -var arts3_SubjN = 0; -var stat_total = 0; -var fl1_total = 0; -var fl2_total = 0; -var sports_total = 0; -var required_total = 0; -var elective1_total = 0; -var elective2_total = 0; -var special_total = 0; -var thesis_total = 0; -var arts_total = apply_total + arts1_total + arts2_total + arts3_total; -var arts_text = 0; -var libarts_text = 0; -var special_text = 0; -var text_total = libarts_text + special_text; -var libarts_media = 0; -var special_media = 0; -var media_total = Math.min(10, libarts_media + special_media); -var media_exe = Math.max(0, libarts_media + special_media - 10); -var libarts_school = 0; -var special_school = 0; -var school_total = media_total + libarts_school + special_school; -var total = arts_total + fl1_total + fl2_total + sports_total + required_total + elective1_total + elective2_total + thesis_total - media_exe; -var arts = 6; //3分野科目の各分野 p.29 -var artsSubN = 2; //3分野科目の各分野 p.29 -var stat = 0; //経済学部の統計学(A) p.31 -var required = 0; //各学部の必修科目 p.38,p.39,p.42,p.43 -var elective = 0; //法学部の選択必修科目 p.42,p.43 -var schooling = 0; //スクーリング p.20 -var arts3sum = 32; -var arts3text = 24; -var fl1 = 8; -var otherarts = 8; -var libarts = 48; -var special = 68; -var thesis = 8; -var spetext = 40; -var textsum = 70; -var stat_text = 0; -var fl1_text = 0; -var fl2_text = 0; -var sports_text = 0; -var fl1_school = 0; -var arts_school = 0; - -window.changeValue = function () { - if (document.getElementById('apply_stat').checked) { $('#stat-text').val(4); } - if (document.getElementById('apply_fl1').checked) { $('#fl1-text').val(8); } - - switch ($('#department option:selected').val()) { //N6/S4/B0 - case '文学部': - stat = 0; - required = 28; - elective = 0; - deptLabel = '文'; - sectLabel = $('#section option:selected').val().charAt(1); - break; - case '経済学部': - stat = 4; - required = 17; - elective = 0; - deptLabel = '経'; - sectLabel = ''; - break; - case '法学部': - stat = 0; - required = 10; - elective = 20; - deptLabel = '法'; - sectLabel = $('#section option:selected').val().charAt(0); - break; - default: - stat = 0; - required = 0; - elective = 0; - deptLabel = '-'; - break; - } +google.charts.load('current', { packages: ['corechart'] });// Google Charts APIの読み込み +// ヘルパー関数 +const min = (a, b) => Math.min(a, b); +const max = (a, b) => Math.max(a, b); +function sum(...numbers) { + return numbers.reduce((acc, num) => acc + num, 0); +} - switch ($('#course option:selected').val()) { //N6/S4/B0 - case '普通課程': - arts = 6; - artsSubN = 2; - schooling = 30; - apply_total = grades[0][0] = 0; - courseLabel = '普'; - break; - case '特別課程': - arts = 4; - artsSubN = 1; - schooling = 22; - apply_total = grades[0][0] = 18; - courseLabel = '特'; - break; - case '学士入学': - arts = 0; - artsSubN = 0; - schooling = 15; - if ($('#department option:selected').val() == '経済学部' && !(document.getElementById('apply_stat').checked)) { - apply_total = grades[0][0] = 36; - } else { - apply_total = grades[0][0] = 40; - } - courseLabel = '学'; - break; - default: - arts = 6; - artsSubN = 2; - schooling = 30; - courseLabel = '-'; - break; +const decisions = { + arts: { major: '総', minor: '3分', id: 1, total: 0, text: 0, school: 0, media: 0, graduate: 32, entry: 28, prog: 0 }, + arts1: { major: '総', minor: '人文', id: 2, total: 0, text: 0, school: 0, media: 0, graduate: 6, prog: 0, subjNum: 0, subjNumReq: 2 }, + arts2: { major: '総', minor: '社会', id: 3, total: 0, text: 0, school: 0, media: 0, graduate: 6, prog: 0, subjNum: 0, subjNumReq: 2 }, + arts3: { major: '総', minor: '科学', id: 4, total: 0, text: 0, school: 0, media: 0, graduate: 6, prog: 0, subjNum: 0, subjNumReq: 2 }, + statT: { major: '総', minor: '統計T',id: 5, total: 0, graduate: 0, prog: 0 }, + artsT: { major: '総', minor: '3分T', id: 6, total: 0, graduate: 24, entry: 18, prog: 0 }, + fl1: { major: '総', minor: '外語', id: 7, total: 0, text: 0, school: 0, media: 0, graduate: 8, entry: 6, prog: 0 }, + liberal: { major: '総', minor: '計', id: 8, total: 0, text: 0, school: 0, media: 0, graduate: 48, entry: 36, approve: 48, submit: 48, prog: 0 }, + required: { major: '専', minor: '必修', id: 9, total: 0, text: 0, school: 0, media: 0, graduate: 0, approve: 10, prog: 0 }, + elective1: { major: '専', minor: '選必', id: 10, total: 0, text: 0, school: 0, media: 0, graduate: 0, prog: 0 }, + specialT: { major: '専', minor: '通信', id: 11, total: 0, graduate: 40, prog: 0 }, + special: { major: '専', minor: '計', id: 12, total: 0, text: 0, school: 0, media: 0, graduate: 68, entry: 7, approve: 35, submit: 60, prog: 0 }, + text: { major: '計', minor: '通信', id: 13, total: 0, graduate: 70, prog: 0 }, + school: { major: '計', minor: 'スク', id: 14, total: 0, graduate: 30, submit: 15, prog: 0 }, + thesis: { major: '論', minor: '卒論', id: 15, total: 0, text: 0, school: 0, media: 0, graduate: 8, prog: 0 }, + otherArts: { major: '総', minor: '他', id: 16, total: 0, text: 0, school: 0, media: 0 }, + fl2: { major: '総', minor: '他語', id: 17, total: 0, text: 0, school: 0, media: 0 }, + sports: { major: '総', minor: '保体', id: 18, total: 0, text: 0, school: 0, media: 0 }, + elective2: { major: '専', minor: '選択', id: 19, total: 0, text: 0, school: 0, media: 0 }, + total: { major: '計', minor: '計', id: 20, total: 0, text: 0, school: 0, media: 0, graduate: 124, prog: 0 }, + apply: { major: '総', minor: '認定', id: 21, total: 0, text: 0 }, + free: { major: '計', minor: '任意', id: 22, total: 0, text: 0, school: 0, media: 0, graduate: 16, prog: 0 }, +}; + +const allUnits = [ + 'apply', 'arts1Done', 'arts2Done', 'arts3Done', 'fl1Done', 'liberalDone', 'requiredDone', 'elective1Done', 'elective2Done', 'thesisDone', + 'artsTDone', 'fl1TDone', 'liberalTDone', 'specialTDone', 'artsSDone', 'fl1SDone', 'liberalSDone', 'specialSDone', + 'arts1None', 'arts2None', 'arts3None', 'artsNone', 'fl1None', 'liberalNone', 'requiredNone', 'elective1None', 'elective2None', 'thesisNone', + 'artsTNone', 'specialTNone', 'textNone', 'schoolNone', 'freeNone','totalUp','totalDown', +]; +const chartUnits = Object.fromEntries(allUnits.map(unit => [unit, 0])); + +const chartData = { + units: chartUnits, + dataUpOuter: { + 'apply': { label: '認定', color: 'gray' }, + 'arts1Done': { label: '人文済', color: 'red' }, + 'arts2Done': { label: '社会済', color: 'red' }, + 'arts3Done': { label: '自然済', color: 'red' }, + 'fl1Done': { label: '必修語済', color: 'red' }, + 'liberalDone': { label: '総合済', color: 'red' }, + 'arts1None': { label: '人文未', color: 'lightsalmon' }, + 'arts2None': { label: '社会未', color: 'lightsalmon' }, + 'arts3None': { label: '自然未', color: 'lightsalmon' }, + 'artsNone': { label: '3分野未', color: 'lightsalmon' }, + 'fl1None': { label: '必修語未', color: 'lightsalmon' }, + 'liberalNone': { label: '総合未', color: 'lightsalmon' }, + 'requiredDone': { label: '必修済', color: 'navy' }, + 'elective1Done': { label: '選択必済', color: 'navy' }, + 'elective2Done': { label: '選択済', color: 'navy' }, + 'requiredNone': { label: '必修未', color: 'lightsteelblue' }, + 'elective1None': { label: '選択必未', color: 'lightsteelblue' }, + 'elective2None': { label: '選択未', color: 'lightsteelblue' }, + 'thesisDone': { label: '卒論済', color: 'fuchsia' }, + 'thesisNone': { label: '卒論未', color: 'pink' }, + }, + dataUpMiddle: { + 'artsDone': { label: '3分野済', color: 'red' , calc: ['apply', 'arts1Done', 'arts2Done', 'arts3Done']}, + 'fl1Done': { label: '必修語済', color: 'red' }, + 'liberalDone': { label: '総合済', color: 'red' }, + 'artsNone': { label: '3分野未', color: 'lightsalmon' , calc: ['arts1None', 'arts2None', 'arts3None', 'artsNone']}, + 'fl1None': { label: '必修語未', color: 'lightsalmon' }, + 'liberalNone': { label: '総合未', color: 'lightsalmon' }, + 'requiredDone': { label: '必修済', color: 'navy' }, + 'elective1Done': { label: '選択必済', color: 'navy' }, + 'elective2Done': { label: '選択済', color: 'navy' }, + 'requiredNone': { label: '必修未', color: 'lightsteelblue' }, + 'elective1None': { label: '選択必未', color: 'lightsteelblue' }, + 'elective2None': { label: '選択未', color: 'lightsteelblue' }, + 'thesisDone': { label: '卒論済', color: 'fuchsia' }, + 'thesisNone': { label: '卒論未', color: 'pink' }, + }, + dataUpInner: { + 'liberalDone': { label: '総合済', color: 'red', calc: ['apply', 'arts1Done', 'arts2Done', 'arts3Done', 'fl1Done', 'liberalDone']}, + 'liberalNone': { label: '総合未', color: 'lightsalmon', calc: ['arts1None', 'arts2None', 'arts3None', 'artsNone', 'fl1None', 'liberalNone']}, + 'specialDone': { label: '専門済', color: 'navy', calc: ['requiredDone', 'elective1Done', 'elective2Done']}, + 'specialNone': { label: '専門未', color: 'lightsteelblue', calc: ['requiredNone', 'elective1None', 'elective2None']}, + 'thesisDone': { label: '卒論済', color: 'fuchsia' }, + 'thesisNone': { label: '卒論未', color: 'pink' }, + }, + dataDownOuter: { + 'apply': { label: '認定', color: 'gray' }, + 'artsTDone': { label: '3分T済', color: 'red' }, + 'fl1TDone': { label: '必語T済', color: 'red' }, + 'liberalTDone': { label: '他総T済', color: 'red' }, + 'specialTDone': { label: '専テキ済', color: 'navy' }, + 'artsTNone': { label: '3分T未', color: 'lightsalmon' }, + 'specialTNone': { label: '専テキ未', color: 'lightsteelblue' }, + 'textNone': { label: 'テキ未', color: 'powderblue' }, + 'artsSDone': { label: '3分スク済', color: 'red' }, + 'fl1SDone': { label: '必語スク済', color: 'red' }, + 'liberalSDone': { label: '他総スク済', color: 'red' }, + 'specialSDone': { label: '専スク済', color: 'navy' }, + 'schoolNone': { label: 'スク未', color: 'wheat' }, + 'freeNone': { label: '任意未', color: 'white' }, + 'thesisDone': { label: '卒論済', color: 'fuchsia' }, + 'thesisNone': { label: '卒論未', color: 'pink' }, + }, + dataDownMiddle: { + 'textDone': { label: 'テキ済', color: 'aqua', calc: ['apply', 'artsTDone', 'fl1TDone', 'liberalTDone', 'specialTDone'] }, + 'textNone': { label: 'テキ未', color: 'powderblue', calc: ['artsTNone', 'specialTNone', 'textNone'] }, + 'schoolDone': { label: 'スク済', color: 'gold', calc: ['artsSDone', 'fl1SDone', 'liberalSDone', 'specialSDone'] }, + 'schoolNone': { label: 'スク未', color: 'wheat' }, + 'freeNone': { label: '任意未', color: 'white' }, + 'thesisDone': { label: '卒論済', color: 'fuchsia' }, + 'thesisNone': { label: '卒論未', color: 'pink' }, } +}; - getForm(); - calcValue(); - updateForm(); +window.showCharts = function () { + const departmentConfig = { + '文学部': { stat: 0, required: 28, elective: 0}, + '経済学部': { stat: 4, required: 17, elective: 0}, + '法学部': { stat: 0, required: 10, elective: 20} + }; + + const selectedDept = $('#department option:selected').val(); + const deptConfig = departmentConfig[selectedDept] || { stat: 0, required: 0, elective: 0}; + + const deptUpdates = { + statT: { graduate: deptConfig.stat }, + required: { graduate: deptConfig.required }, + elective1: { graduate: deptConfig.elective } + }; + + Object.keys(deptUpdates).forEach(condition => { + Object.assign(decisions[condition], deptUpdates[condition]); + }); + + const courseConfig = { + '普通課程': { arts: 6, artsSubN: 2, school: 30, applyText: 0}, + '特別課程': { arts: 4, artsSubN: 1, school: 22, applyText: 18}, + '学士入学': { + arts: 0, artsSubN: 0, school: 15, + applyText: ($('#department option:selected').val() === '経済学部' && !document.getElementById('apply_stat').checked) ? 36 : 40 + } + }; -} + const selectedCourse = $('#course option:selected').val(); + const crsConfig = courseConfig[selectedCourse] || { arts: 6, artsSubN: 2, school: 30, applyText: 0}; -window.calcValue = function () { - arts1_SubjN = subjNum[1]; - arts2_SubjN = subjNum[2]; - arts3_SubjN = subjNum[3]; - stat_text = Math.min(4, grades[4][0]); - arts_text = (apply_total == 36) ? stat_text : ((courseLabel == '学') ? 0 : (grades[1][0] + grades[2][0] + grades[3][0])); - fl1_text = (document.getElementById('apply_fl1').checked) ? 8 : Math.min(6, grades[5][0]); - fl2_text = (courseLabel == '学') ? 0 : Math.min(4, grades[6][0]); - sports_text = (courseLabel == '学') ? 0 : Math.min(4, grades[7][0]); - libarts_text = Math.min(40, apply_total + arts_text) + fl1_text + fl2_text + sports_text; - special_text = grades[8][0] + grades[9][0] + grades[10][0]; - libarts_media = Math.min(10, grades[1][2] + grades[2][2] + grades[3][2] + grades[5][2] + grades[6][2]); - special_media = Math.min(10, grades[8][2] + grades[9][2] + grades[10][2]); - media_total = Math.min(10, libarts_media + special_media); - media_exe = Math.max(0, grades[1][2] + grades[2][2] + grades[3][2] + grades[5][2] + grades[6][2] + grades[8][2] + grades[9][2] + grades[10][2] - 10); - media_max = Math.max(grades[1][2], grades[2][2], grades[3][2], grades[5][2], grades[6][2], grades[8][2], grades[9][2], grades[10][2]); - arts_school = (courseLabel == '学') ? 0 : Math.min(12, grades[1][1] + grades[2][1] + grades[3][1] + grades[1][2] + grades[2][2] + grades[3][2]); - artsch_exe = (courseLabel == '学') ? 0 : Math.max(0, grades[1][1] + grades[2][1] + grades[3][1] + grades[1][2] + grades[2][2] + grades[3][2] - 12); - artsch_max = (courseLabel == '学') ? 0 : Math.max(grades[1][1], grades[2][1], grades[3][1]); - fl1_school = Math.min(4, grades[5][1] + grades[5][2]); - fl2_school = Math.min(4, grades[6][1] + grades[6][2]); - sports_school = (courseLabel == '学') ? 0 : Math.min(4, grades[7][1]); - otherarts_school = fl1_school + fl2_school + sports_school - special_school = Math.min(28, grades[8][1] + grades[9][1] + grades[10][1] + special_media); - if (grades[1][2] == media_max || grades[2][2] == media_max || grades[3][2] == media_max) { arts_school = arts_school - media_exe } - else if (grades[5][2] == media_max || grades[6][2] == media_max || grades[7][2] == media_max) { otherarts_school = otherarts_school - media_exe } - else if (grades[8][2] == media_max || grades[9][2] == media_max || grades[10][2] == media_max) { special_school = special_school - media_exe } - libarts_school = arts_school + otherarts_school; - arts1_total = (courseLabel == '学') ? 0 : grades[1][0] + grades[1][1] + grades[1][2]; - arts2_total = (courseLabel == '学') ? 0 : grades[2][0] + grades[2][1] + grades[2][2]; - arts3_total = (courseLabel == '学') ? ((apply_total == 36) ? stat_text:0) : grades[3][0] + grades[3][1] + grades[3][2]; - if (grades[1][1] == artsch_max) { arts1_total = arts1_total - artsch_exe } - else if (grades[2][1] == artsch_max) { arts2_total = arts2_total - artsch_exe } - else if (grades[3][1] == artsch_max) { arts3_total = arts3_total - artsch_exe } - stat_total = grades[4][0] + grades[4][1] + grades[4][2]; - fl1_total = Math.min(8, fl1_text + fl1_school); - fl2_total = (courseLabel == '学') ? 0 : Math.min(4, fl2_text + fl2_school); - sports_total = (courseLabel == '学') ? 0 : Math.min(4, sports_text + sports_school); - required_total = grades[8][0] + grades[8][1] + grades[8][2]; - elective1_total = grades[9][0] + grades[9][1] + grades[9][2]; - elective2_total = grades[10][0] + grades[10][1] + grades[10][2]; - thesis_total = Math.min(8, grades[11][0]); - arts_total = Math.min(40,apply_total + arts_text + arts_school); - libarts_total = Math.min(48,arts_total + fl1_total + fl2_total + sports_total); - special_total = required_total + elective1_total + elective2_total; - text_total = libarts_text + special_text; - school_total = libarts_school + special_school; - total = Math.min(text_total + school_total + thesis_total, libarts_total + special_total + thesis_total); - - $('#apply-text').text(apply_total); - - $('#ID11001-unit').text(arts_total); - $('#ID11101-unit').text(arts1_total); - $('#ID11201-unit').text(arts2_total); - $('#ID11301-unit').text(arts3_total); - $('#ID11311-unit').text(stat_text); - $('#ID12001-unit').text(Math.min(40,arts_text + apply_total)); - $('#ID20001-unit').text(fl1_total); - $('#ID30001-unit').text(libarts_total); - $('#ID40001-unit').text(required_total + elective1_total + elective2_total); - $('#ID41001-unit').text(required_total); - $('#ID42001-unit').text(elective1_total); - $('#ID43001-unit').text(special_text); - $('#ID50001-unit').text(text_total); - $('#ID60001-unit').text(school_total); - $('#ID70001-unit').text(thesis_total); - - $('#ID11001-req').text(arts3sum); - $('#ID11101-req').text(arts); - $('#ID11201-req').text(arts); - $('#ID11301-req').text(arts); - $('#ID11311-req').text(stat); - $('#ID12001-req').text(arts3text); - $('#ID20001-req').text(fl1); - $('#ID30001-req').text(libarts); - $('#ID40001-req').text(special); - $('#ID41001-req').text(required); - $('#ID42001-req').text(elective); - $('#ID43001-req').text(spetext); - $('#ID50001-req').text(textsum); - $('#ID60001-req').text(schooling); - $('#ID70001-req').text(thesis); - - $('#ID60001-admit').text(schooling); - - $('#total_units').text(total); - $('#total_units2').text(total); - - var arts_total_prog = Math.min(arts_total / 32, 1); - var arts1_total_prog = (arts == 0 ? 1 : Math.min(arts1_total / arts, arts1_SubjN >= artsSubN ? 1 : 0.99)); - var arts2_total_prog = (arts == 0 ? 1 : Math.min(arts2_total / arts, arts2_SubjN >= artsSubN ? 1 : 0.99)); - var arts3_total_prog = (arts == 0 ? 1 : Math.min(arts3_total / arts, arts3_SubjN >= artsSubN ? 1 : 0.99)); - var stat_text_prog = (stat == 0 ? 1 : Math.min(stat_text / stat, 1)); - var arts_text_prog = Math.min((arts_text + apply_total) / 24, 1); - var fl1_total_prog = Math.min(fl1_total / 8, 1); - var libarts_total_prog = Math.min(libarts_total / 48, 1); - var special_total_prog = Math.min(special_total / 68, 1); - var required_total_prog = (required == 0 ? 1 : Math.min(required_total / required, 1)); - var elective_total_prog = (elective == 0 ? 1 : Math.min(elective1_total / elective, 1)); - var special_text_prog = Math.min(special_text / 40, 1); - var text_total_prog = Math.min(text_total / 70, 1); - var school_total_prog = Math.min(school_total / schooling, 1); - var thesis_total_prog = Math.min(thesis_total / 8, 1); - - $('#ID11001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(arts_total_prog)); - $('#ID11101-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(arts1_total_prog)); - $('#ID11201-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(arts2_total_prog)); - $('#ID11301-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(arts3_total_prog)); - $('#ID11311-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(stat_text_prog)); - $('#ID12001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(arts_text_prog)); - $('#ID20001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(fl1_total_prog)); - $('#ID30001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(libarts_total_prog)); - $('#ID40001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(special_total_prog)); - $('#ID41001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(required_total_prog)); - $('#ID42001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(elective_total_prog)); - $('#ID43001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(special_text_prog)); - $('#ID50001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(text_total_prog)); - $('#ID60001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(school_total_prog)); - $('#ID70001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(thesis_total_prog)); - - arts_total >= 28 ? document.getElementById('ID11001-entry').className = 'done' : document.getElementById('ID11001-entry').className = 'none'; - arts_total >= arts3sum ? document.getElementById('ID11001-req').className = 'done' : document.getElementById('ID11001-req').className = 'none'; - (arts1_total >= arts && arts1_SubjN >= artsSubN) ? document.getElementById('ID11101-req').className = 'done' : document.getElementById('ID11101-req').className = 'none'; - (arts2_total >= arts && arts2_SubjN >= artsSubN) ? document.getElementById('ID11201-req').className = 'done' : document.getElementById('ID11201-req').className = 'none'; - (arts3_total >= arts && arts3_SubjN >= artsSubN) ? document.getElementById('ID11301-req').className = 'done' : document.getElementById('ID11301-req').className = 'none'; - stat_text >= stat ? document.getElementById('ID11311-req').className = 'done' : document.getElementById('ID11311-req').className = 'none'; - (arts_text + apply_total) >= 18 ? document.getElementById('ID12001-entry').className = 'done' : document.getElementById('ID12001-entry').className = 'none'; - (arts_text + apply_total) >= arts3text ? document.getElementById('ID12001-req').className = 'done' : document.getElementById('ID12001-req').className = 'none'; - fl1_total >= 6 ? document.getElementById('ID20001-entry').className = 'done' : document.getElementById('ID20001-entry').className = 'none'; - fl1_total >= fl1 ? document.getElementById('ID20001-req').className = 'done' : document.getElementById('ID20001-req').className = 'none'; - fl1_total >= fl1 ? document.getElementById('ID20001-req').className = 'done' : document.getElementById('ID20001-req').className = 'none'; - libarts_total >= 36 ? document.getElementById('ID30001-entry').className = 'done' : document.getElementById('ID30001-entry').className = 'none'; - libarts_total >= libarts ? document.getElementById('ID30001-submit').className = 'done' : document.getElementById('ID30001-submit').className = 'none'; - libarts_total >= libarts ? document.getElementById('ID30001-admit').className = 'done' : document.getElementById('ID30001-admit').className = 'none'; - libarts_total >= libarts ? document.getElementById('ID30001-req').className = 'done' : document.getElementById('ID30001-req').className = 'none'; - special_total >= 7 ? document.getElementById('ID40001-entry').className = 'done' : document.getElementById('ID40001-entry').className = 'none'; - special_total >= 35 ? document.getElementById('ID40001-submit').className = 'done' : document.getElementById('ID40001-submit').className = 'none'; - special_total >= 60 ? document.getElementById('ID40001-admit').className = 'done' : document.getElementById('ID40001-admit').className = 'none'; - special_total >= special ? document.getElementById('ID40001-req').className = 'done' : document.getElementById('ID40001-req').className = 'none'; - required_total >= 10 ? document.getElementById('ID41001-submit').className = 'done' : document.getElementById('ID41001-submit').className = 'none'; - required_total >= required ? document.getElementById('ID41001-req').className = 'done' : document.getElementById('ID41001-req').className = 'none'; - elective1_total >= elective ? document.getElementById('ID42001-req').className = 'done' : document.getElementById('ID42001-req').className = 'none'; - special_text >= spetext ? document.getElementById('ID43001-req').className = 'done' : document.getElementById('ID43001-req').className = 'none'; - text_total >= textsum ? document.getElementById('ID50001-req').className = 'done' : document.getElementById('ID50001-req').className = 'none'; - school_total >= schooling ? document.getElementById('ID60001-admit').className = 'done' : document.getElementById('ID60001-admit').className = 'none'; - school_total >= schooling ? document.getElementById('ID60001-req').className = 'done' : document.getElementById('ID60001-req').className = 'none'; - thesis_total >= thesis ? document.getElementById('ID70001-req').className = 'done' : document.getElementById('ID70001-req').className = 'none'; - - $('#ID30001-prog').text(new Intl.NumberFormat('ja', { style: 'percent' }).format(libarts_total_prog)); + const courseUpdates = { + arts1: { graduate: crsConfig.arts, subjNumReq: crsConfig.artsSubN}, + arts2: { graduate: crsConfig.arts, subjNumReq: crsConfig.artsSubN}, + arts3: { graduate: crsConfig.arts, subjNumReq: crsConfig.artsSubN}, + school: { graduate: crsConfig.school, submit: crsConfig.school} + }; + Object.keys(courseUpdates).forEach(condition => { + Object.assign(decisions[condition], courseUpdates[condition]); + }); + + calcValue(); + setChartData(); + callDrawChart(); } -google.charts.load('current', { 'packages': ['corechart'] }); -google.charts.setOnLoadCallback(drawChart); -function drawChart() { - //control is here - let larguraGraficoFora = 240; - let alturaGraficoFora = 240; - let furoGraficoFora = 0.75; - let furoGraficoFora2 = 0.5; - let furoGraficoFora3 = 0.25; - var temp = 11; - - data1 = google.visualization.arrayToDataTable([ - ['Category', 'Units'], - ['認定', 0], // gray - ['人文済', 0], // maroon - ['人文未', 6], // indianred - ['社会済', 0], // olive - ['社会未', 6], // palegoldenrod - ['自然済', 0], // green - ['自然未', 6], // aquamarine - ['3分野未', 14], // lightsalmon - ['必修語済', 0], // lime - ['必修語未', 8], // yellowgreen - ['総合済', 0], // red - ['総合未', 8], // lightsalmon - ['必修済', 0], // navy - ['必修未', 0], // steelblue - ['選択必済', 0], // purple - ['選択必未', 0], // plum - ['選択済', 0], // teal - ['選択未', 68], // darkturquoise - ['卒論済', 0], // fuchsia - ['卒論未', 8] // pink - ]); - - data2 = google.visualization.arrayToDataTable([ - ['Category', 'Units'], - ['3分野済', 0], - ['3分野未', 32], - ['必修語済', 0], - ['必修語未', 8], - ['総合済', 0], - ['総合未', 8], - ['必修済', 0], - ['必修未', 0], - ['選択必済', 0], - ['選択必未', 0], - ['選択済', 0], - ['選択未', 68], - ['卒論済', 0], - ['卒論未', 8] - ]); - - data3 = google.visualization.arrayToDataTable([ - ['Category', 'Units'], - ['総合済', 0], - ['総合未', 48], - ['専門済', 0], - ['専門未', 68], - ['卒論済', 0], - ['卒論未', 8] - ]); - - data4 = google.visualization.arrayToDataTable([ - ['Category', 'Units'], - ['認定', 0], - ['3分T済', 0], - ['3分T未', 24], - ['必語T済', 0], - ['他総T済', 0], - ['専テキ済', 0], - ['専テキ未', 40], - ['テキ未', 6], - ['3分スク済', 0], - ['必語スク済', 0], - ['専スク済', 0], - ['スク未', 30], - ['任意未', 16], - ['卒論済', 0], - ['卒論未', 8] - ]); - - data5 = google.visualization.arrayToDataTable([ - ['Category', 'Units'], - ['テキ済', 0], - ['テキ未', 70], - ['スク済', 0], - ['スク未', 30], - ['任意未', 16], - ['卒論済', 0], - ['卒論未', 8] - ]); - - var options1 = { - width: larguraGraficoFora, - height: alturaGraficoFora, - chartArea: { left: 0, top: 0, width: '100%', height: '100%' }, - pieHole: furoGraficoFora, - colors: ['gray', 'maroon', 'indianred', 'olive', 'palegoldenrod', 'green', 'aquamarine', 'lightsalmon', 'lime', 'lightgreen', 'gray', 'silver', 'teal', 'darkturquoise', 'purple', 'plum', 'navy', 'lightsteelblue', 'fuchsia', 'pink'], - pieSliceText: 'value', - legend: 'none' +function calcValue () { + // ヘルパー関数 + const clamp = (condition, ifTrue, ifFalse) => condition ? ifTrue : ifFalse; + const calcTotal = (data = [], indices = []) => { + if (!Array.isArray(data)) { + return 0; + } + // インデックスが指定されていない場合、デフォルトで全要素の合計を計算 + if (indices.length === 0) { + return data.reduce((sum, value) => sum + (parseInt(value) || 0), 0); + } + // インデックスが指定されている場合、そのインデックスに基づいて合計を計算 + return indices.reduce((sum, index) => sum + (parseInt(data[index]) || 0), 0); + }; + const course = profile.value.course; + //console.log(grades); + + [decisions.arts1.subjNum, decisions.arts2.subjNum, decisions.arts3.subjNum] = [subjNum[1], subjNum[2], subjNum[3]]; + // テキストの計算 + const applyText = decisions.apply.text = min(40, units[0][0]); + decisions.arts1.text = min(20, units[1][0]); + decisions.arts2.text = min(20, units[2][0]); + decisions.arts3.text = min(20, units[3][0]); + decisions.statT.text = min(4, units[4][0]); + decisions.fl1.text = min(6, units[5][0]); + decisions.fl2.text = min(4, units[6][0]); + decisions.sports.text = min(4, units[7][0]); + decisions.special.text = min(68, sum(units[8][0],units[9][0],units[10][0])); + + decisions.arts.text = min(40, sum(decisions.arts1.text,decisions.arts2.text,decisions.arts3.text)); + decisions.arts.text = min(40, applyText + clamp(applyText == 36, decisions.statT.text, decisions.arts.text)); + decisions.fl1.text = min(8,clamp(document.getElementById('apply_fl1').checked, 8, decisions.fl1.text)); + decisions.otherArts.text = min(8, sum(decisions.fl2.text,decisions.sports.text)); + decisions.liberal.text = min(48, sum(decisions.arts.text,decisions.otherArts.text,decisions.fl1.text)); + decisions.total.text = min(86, decisions.liberal.text + decisions.special.text); + decisions.free.text = max(0, sum(decisions.total.text, max(0, decisions.artsT.graduate - decisions.artsT.total), max(0, decisions.specialT.graduate - decisions.specialT.total)) - decisions.text.graduate); + + // スクーリングの計算 + decisions.arts1.school = min(12, units[1][1]); + decisions.arts2.school = min(12, units[2][1]); + decisions.arts3.school = min(12, units[3][1]); + decisions.fl1.school = min(4, units[5][1]); + decisions.fl2.school = min(4, units[6][1]); + decisions.sports.school = min(4, units[7][1]); + decisions.special.school = min(28, sum(units[8][1],units[9][1],units[10][1])); + decisions.arts1.media = min(10, units[1][2]); + decisions.arts2.media = min(10, units[2][2]); + decisions.arts3.media = min(10, units[3][2]); + decisions.fl1.media = min(2, units[5][2]); + decisions.special.media = min(10, sum(units[8][2],units[9][2],units[10][2])); + const medias = [decisions.arts1.media,decisions.arts2.media,decisions.arts3.media,decisions.fl1.media,decisions.special.media]; + [decisions.arts1.media,decisions.arts2.media,decisions.arts3.media,decisions.fl1.media,decisions.special.media] = adjustValues(medias, 10); + + decisions.arts1.school = min(12, sum(decisions.arts1.school,decisions.arts1.media)); + decisions.arts2.school = min(12, sum(decisions.arts2.school,decisions.arts2.media)); + decisions.arts3.school = min(12, sum(decisions.arts3.school,decisions.arts3.media)); + decisions.fl1.school = min(4, sum(decisions.fl1.school,decisions.fl1.media)); + decisions.special.school = min(28, sum(decisions.special.school,decisions.special.media)); + + const artsSchools = [decisions.arts1.school,decisions.arts2.school,decisions.arts3.school]; + [decisions.arts1.school,decisions.arts2.school,decisions.arts3.school] = adjustValues(artsSchools, 12); + decisions.arts.school = min(12, sum(decisions.arts1.school, decisions.arts2.school, decisions.arts3.school)); + decisions.otherArts.school = min(8, sum(decisions.fl2.school,decisions.sports.school)); + decisions.liberal.school = min(24, sum(decisions.arts.school, decisions.fl1.school, decisions.otherArts.school)); + decisions.special.school = min(28, decisions.special.school); + + // スクーリングの調整 + function adjustValues(values, max) { + let sum = values.reduce((acc, val) => acc + val, 0); // 合計を計算 + while (sum > max) { // 合計がmax以内になるまでループ + let maxIndex = values.indexOf(Math.max(...values)); // 最大値を取得 + values[maxIndex] -= 2; // 最大値から2を引く + sum = values.reduce((acc, val) => acc + val, 0); // 新しい合計を計算 + } + return values; // 結果を返す + } + decisions.total.school = min(46, decisions.liberal.school + decisions.special.school); + decisions.free.school = max(0, decisions.total.school - decisions.school.graduate) + + // 合計の計算 + decisions.apply.total = min(40, decisions.apply.text); + decisions.arts.total = min(40, sum(decisions.arts.text, decisions.arts.school)); + decisions.arts1.total = min(20, sum(decisions.arts1.text, decisions.arts1.school)); + decisions.arts2.total = min(20, sum(decisions.arts2.text, decisions.arts2.school)); + decisions.arts3.total = min(20, sum(decisions.arts3.text, decisions.arts3.school)); + decisions.statT.total = min(4, decisions.statT.text); + decisions.artsT.total = min(40, decisions.arts.text); + decisions.fl1.total = min(8, sum(decisions.fl1.text,decisions.fl1.school)); + decisions.fl2.total = min(4, decisions.fl2.text + decisions.fl2.school); + decisions.sports.total = min(4, decisions.sports.text + decisions.sports.school); + decisions.otherArts.total = min(8, decisions.otherArts.text + decisions.otherArts.school); + decisions.liberal.total = min(48, decisions.liberal.text + decisions.liberal.school); + decisions.required.total = min(68, calcTotal(units[8])); + decisions.elective1.total = min(68, calcTotal(units[9])); + decisions.elective2.total = min(68, calcTotal(units[10])); + decisions.specialT.total = min(68, decisions.special.text); + decisions.special.total = min(68, decisions.special.text + decisions.special.school); + decisions.text.total = min(86, decisions.liberal.text + decisions.special.text); + decisions.school.total = min(46, decisions.liberal.school + decisions.special.school); + decisions.thesis.total = min(8, units[11][0]); + decisions.total.total = min(decisions.text.total + decisions.school.total, decisions.liberal.total + decisions.special.total)+ decisions.thesis.total; + decisions.free.total = min(16, sum(decisions.free.text,decisions.free.school)); + + const capAtZero = (rawTotal) => clamp(course == '学士入学', 0, rawTotal); + const propertiesToCap = ['text','school','total']; + const itemsToCap = ['arts1','arts2','arts3','fl2','sports']; + propertiesToCap.forEach(prop => { + itemsToCap.forEach(item => { + decisions[item][prop] = capAtZero(decisions[item][prop]); + }); + }); + + // 進捗の計算 + const updateProg = (item) => { + const prog = item.graduate === 0 ? 1 : Math.min(item.total / item.graduate, 1); + item.prog = (item.subjNumReq > 0 && prog === 1) ? (item.subjNum >= item.subjNumReq ? prog : 0.99) : prog; + }; + const getElementId = (key, suffix) => `${key}-${suffix}`; + const formatter = new Intl.NumberFormat('ja', { style: 'percent' }); + + //console.log(decisions); + + // プロパティの設定 + // ここあとで直す + const properties = { + graduate: ['total', 'graduate'], + entry: ['total', 'entry'], + approve: ['total', 'approve'], + submit: ['total', 'submit'] }; - var options2 = { - width: larguraGraficoFora * furoGraficoFora, - height: alturaGraficoFora * furoGraficoFora, - chartArea: { left: 0, top: 0, width: '100%', height: '100%' }, - pieHole: furoGraficoFora2 / furoGraficoFora, - colors: ['red', 'lightsalmon', 'lime', 'lightgreen', 'gray', 'silver', 'teal', 'darkturquoise', 'purple', 'plum', 'navy', 'lightsteelblue', 'fuchsia', 'pink'], - pieSliceText: 'value', - backgroundColor: 'transparent', - legend: 'none' + // 関数定義 + const updateProperties = (item, key) => { + const propertyKeys = ['total', 'entry', 'approve', 'submit', 'graduate', 'prog']; + propertyKeys.forEach(property => { + const elementId = getElementId(key, property); + const value = property === 'prog' ? formatter.format(item[property]) : item[property]; + $(document.getElementById(elementId)).text(value !== undefined ? value : ''); + }); }; - var options3 = { - width: larguraGraficoFora * furoGraficoFora2, - height: alturaGraficoFora * furoGraficoFora2, - chartArea: { left: 0, top: 0, width: '100%', height: '100%' }, - pieHole: furoGraficoFora3 / furoGraficoFora2, - colors: ['red', 'lightsalmon', 'navy', 'lightsteelblue', 'fuchsia', 'pink'], - pieSliceText: 'value', - backgroundColor: 'transparent', - legend: 'none' + const updateConditions = (item, key) => { + Object.entries(properties).forEach(([status, [totalProp, compareProp]]) => { + if (item[compareProp] !== undefined) { + const id = `${key}-${status}`; + const condition = item[totalProp] >= item[compareProp]; + document.getElementById(id).className = condition ? 'done' : 'none'; + } + }); }; - var options4 = { - width: larguraGraficoFora, - height: alturaGraficoFora, + // メイン処理 + Object.entries(decisions) + .filter(([key, item]) => item.id <= 15) // id が15以下のエントリーを選択 + .forEach(([key, item]) => { + updateProg(item); // updateProg 関数を適用 + updateProperties(item, key); + updateConditions(item, key); + }); + + $('#Apply-text').text(applyText); +} + +function setChartData () { + chartData.units.apply = decisions.apply.total; + chartData.units.arts1Done = decisions.arts1.total; + chartData.units.arts2Done = decisions.arts2.total; + chartData.units.arts3Done = decisions.arts3.total; + chartData.units.fl1Done = decisions.fl1.total; + chartData.units.liberalDone = decisions.otherArts.total; + chartData.units.requiredDone = decisions.required.total; + chartData.units.elective1Done = decisions.elective1.total; + chartData.units.elective2Done = decisions.elective2.total; + chartData.units.thesisDone = decisions.thesis.total; + chartData.units.artsTDone = sum(chartData.units.arts1Done,chartData.units.arts2Done,chartData.units.arts3Done); + chartData.units.fl1TDone = decisions.fl1.text; + chartData.units.liberalTDone = decisions.otherArts.text; + chartData.units.specialTDone = decisions.special.text; + chartData.units.artsSDone = decisions.arts.school; + chartData.units.fl1SDone = decisions.fl1.school; + chartData.units.liberalSDone = decisions.otherArts.school; + chartData.units.specialSDone = decisions.special.school; + chartData.units.arts1None = max(0, decisions.arts1.graduate - decisions.arts1.total); + chartData.units.arts2None = max(0, decisions.arts2.graduate - decisions.arts2.total); + chartData.units.arts3None = max(0, decisions.arts3.graduate - decisions.arts3.total) + + decisions.statT.graduate>0 ? max(0,decisions.statT.graduate - decisions.statT.total):0; + chartData.units.fl1None = max(0, decisions.fl1.graduate - decisions.fl1.total); + const applyAlloc = chartData.units.apply; + const arts1Alloc = sum(decisions.arts1.total,chartData.units.arts1None); + const arts2Alloc = sum(decisions.arts2.total,chartData.units.arts2None); + const arts3Alloc = sum(decisions.arts3.total,chartData.units.arts3None); + const artsNone = chartData.units.artsNone = max(0, decisions.arts.graduate - sum(applyAlloc,arts1Alloc,arts2Alloc,arts3Alloc)); + const artsAlloc = sum(applyAlloc,arts1Alloc,arts2Alloc,arts3Alloc,artsNone); + const fl1Alloc = sum(decisions.fl1.total,chartData.units.fl1None); + chartData.units.liberalNone = max(0, decisions.liberal.graduate - sum(artsAlloc,fl1Alloc,decisions.otherArts.total)); + chartData.units.requiredNone = max(0, decisions.required.graduate - decisions.required.total); + chartData.units.elective1None = max(0, decisions.elective1.graduate - decisions.elective1.total); + const requiredAlloc = sum(decisions.required.total,chartData.units.requiredNone); + const elective1Alloc = sum(decisions.elective1.total,chartData.units.elective1None); + chartData.units.elective2None = max(0, decisions.special.graduate - sum(requiredAlloc,elective1Alloc,decisions.elective2.total)); + chartData.units.thesisNone = max(0, decisions.thesis.graduate - decisions.thesis.total); + const thesisAlloc = sum(decisions.thesis.total, chartData.units.thesisNone); + chartData.units.artsTNone = max(0, decisions.artsT.graduate - decisions.artsT.total) + + (decisions.statT.graduate>0 ? max(0,decisions.statT.graduate - decisions.statT.total) : 0); + chartData.units.specialTNone = max(0, decisions.specialT.graduate - decisions.specialT.total); + const artsTAlloc = sum(decisions.artsT.total,chartData.units.artsTNone); + const specialTAlloc = sum(decisions.specialT.total,chartData.units.specialTNone); + chartData.units.textNone = max(0, decisions.text.graduate - sum(artsTAlloc,specialTAlloc)); + chartData.units.schoolNone = max(0, decisions.school.graduate - decisions.school.total); + const textAlloc = sum(artsTAlloc, specialTAlloc, chartData.units.textNone); + const schoolAlloc = sum(decisions.school.total, chartData.units.schoolNone); + chartData.units.totalUp = sum( + chartData.units.apply,chartData.units.arts1Done,chartData.units.arts2Done,chartData.units.arts3Done,chartData.units.fl1Done,chartData.units.liberalDone, + chartData.units.requiredDone,chartData.units.elective1Done,chartData.units.elective2Done,chartData.units.thesisDone); + chartData.units.totalDown = sum( + chartData.units.apply,chartData.units.artsTDone,chartData.units.fl1TDone,chartData.units.liberalTDone,chartData.units.specialTDone, + chartData.units.liberalSDone,chartData.units.specialSDone,chartData.units.thesisDone); + chartData.units.freeNone = max(0, decisions.total.graduate - sum(chartData.units.totalDown,chartData.units.artsTNone,chartData.units.specialTNone,chartData.units.textNone,chartData.units.schoolNone,chartData.units.thesisNone)); +} + +// グラフを描画する関数 +function drawChart() { + const [WidthOutside, HeightOutside] = [240, 240]; + const [ChartSize, ChartSizeRatioOuter, ChartSizeRatioMiddle, ChartSizeRatioInner] = [1, 0.75, 0.5, 0.25]; + + // 基本設定オプション + const baseOptions = { chartArea: { left: 0, top: 0, width: '100%', height: '100%' }, - pieHole: furoGraficoFora, - colors: ['gray', 'red', 'lightsalmon', 'lime', 'silver', 'navy', 'lightsteelblue', 'powderblue', 'red', 'lime', 'navy', 'wheat', 'white', 'fuchsia', 'pink'], pieSliceText: 'value', - legend: 'none' + legend: 'none', }; - var options5 = { - width: larguraGraficoFora * furoGraficoFora, - height: alturaGraficoFora * furoGraficoFora, - chartArea: { left: 0, top: 0, width: '100%', height: '100%' }, - pieHole: furoGraficoFora2 / furoGraficoFora, - colors: ['aqua', 'powderblue', 'gold', 'wheat', 'white', 'fuchsia', 'pink'], - pieSliceText: 'value', - backgroundColor: 'transparent', - legend: 'none' + // グラフオプションを生成する関数 + const getChartOptions = (chartRatio, pieHoleRatio) => ({ + ...baseOptions, + width: WidthOutside * chartRatio, + height: HeightOutside * chartRatio, + pieHole: pieHoleRatio, + colors: [], + backgroundColor: pieHoleRatio === 1 ? undefined : 'transparent', + }); + + // 各グラフのオプション設定 + const options = { + UpOuter: getChartOptions(ChartSize, ChartSizeRatioOuter), + UpMiddle: getChartOptions(ChartSizeRatioOuter, ChartSizeRatioMiddle / ChartSizeRatioOuter), + UpInner: getChartOptions(ChartSizeRatioMiddle, ChartSizeRatioInner / ChartSizeRatioMiddle), + DownOuter: getChartOptions(ChartSize, ChartSizeRatioOuter), + DownMiddle: getChartOptions(ChartSizeRatioOuter, ChartSizeRatioMiddle / ChartSizeRatioOuter), }; - var chart1 = new google.visualization.PieChart(document.getElementById('donutchart_1')); - chart1.draw(data1, options1); - - var chart2 = new google.visualization.PieChart(document.getElementById('donutchart_2')); - chart2.draw(data2, options2); - - var chart3 = new google.visualization.PieChart(document.getElementById('donutchart_3')); - chart3.draw(data3, options3); - - var chart4 = new google.visualization.PieChart(document.getElementById('donutchart_4')); - chart4.draw(data4, options4); - - var chart5 = new google.visualization.PieChart(document.getElementById('donutchart_5')); - chart5.draw(data5, options5); - - var rewriteChart = function () { - changeValue(); - calcValue(); - data1.setValue(0, 1, apply_total); - data1.setValue(1, 1, arts1_total); - data1.setValue(3, 1, arts2_total); - data1.setValue(5, 1, arts3_total); - data1.setValue(8, 1, fl1_total); - data1.setValue(10, 1, fl2_total + sports_total); - data1.setValue(12, 1, required_total); - data1.setValue(14, 1, elective1_total); - data1.setValue(16, 1, elective2_total); - data1.setValue(18, 1, thesis_total); - - data2.setValue(0, 1, arts_total); - data2.setValue(2, 1, fl1_total); - data2.setValue(4, 1, fl2_total + sports_total); - data2.setValue(6, 1, required_total); - data2.setValue(8, 1, elective1_total); - data2.setValue(10, 1, elective2_total); - data2.setValue(12, 1, thesis_total); - - data3.setValue(0, 1, arts_total + fl1_total + fl2_total + sports_total); - data3.setValue(2, 1, required_total + elective1_total + elective2_total); - data3.setValue(4, 1, thesis_total); - - data4.setValue(0, 1, Math.max(0, apply_total)); - data4.setValue(1, 1, Math.max(0, arts_text)); - data4.setValue(3, 1, Math.max(0, fl1_text)); - data4.setValue(4, 1, Math.max(0, fl2_text + sports_text)); - data4.setValue(5, 1, Math.max(0, special_text)); - data4.setValue(8, 1, Math.max(0, arts_school)); - data4.setValue(9, 1, Math.max(0, otherarts_school)); - data4.setValue(10, 1, Math.max(0, special_school)); - data4.setValue(13, 1, Math.max(0, thesis_total)); - - data5.setValue(0, 1, text_total); - data5.setValue(2, 1, school_total); - data5.setValue(5, 1, thesis_total); - - data1.setValue(2, 1, Math.max(0, arts - arts1_total)); - data1.setValue(4, 1, Math.max(0, arts - arts2_total)); - data1.setValue(6, 1, Math.max(0, arts - arts3_total)); - data1.setValue(7, 1, Math.max(0, arts3sum - apply_total - Math.max(arts, arts1_total) - Math.max(arts, arts2_total) - Math.max(arts, arts3_total))); - data1.setValue(9, 1, Math.max(0, fl1 - fl1_total)); - data1.setValue(11, 1, Math.max(0, otherarts - (Math.max(0, arts_total - arts3sum) + fl2_total + sports_total))); - data1.setValue(13, 1, Math.max(0, required - required_total)); - data1.setValue(15, 1, Math.max(0, elective - elective1_total)); - data1.setValue(17, 1, Math.max(0, special - required - Math.max(0, required_total - required) - elective - Math.max(0, elective1_total - elective) - elective2_total)); - data1.setValue(19, 1, Math.max(0, (thesis - thesis_total))); - - data2.setValue(1, 1, Math.max(0, arts3sum - arts_total)); - data2.setValue(3, 1, Math.max(0, fl1 - fl1_total)); - data2.setValue(5, 1, Math.max(0, otherarts - (Math.max(0, arts_total - arts3sum) + fl2_total + sports_total))); - data2.setValue(7, 1, Math.max(0, required - required_total)); - data2.setValue(9, 1, Math.max(0, elective - elective1_total)); - data2.setValue(11, 1, Math.max(0, special - required - Math.max(0, required_total - required) - elective - Math.max(0, elective1_total - elective) - elective2_total)); - data2.setValue(13, 1, Math.max(0, thesis - thesis_total)); - - data3.setValue(1, 1, Math.max(0, libarts - (arts_total + fl1_total + fl2_total + sports_total))); - data3.setValue(3, 1, Math.max(0, special - (required_total + elective1_total + elective2_total))); - data3.setValue(5, 1, Math.max(0, (thesis - thesis_total))); - - data4.setValue(2, 1, Math.max(0, (apply_total >= 36) ? 0 : (24 - arts_text - apply_total))); - data4.setValue(6, 1, Math.max(0, 40 - special_text)); - data4.setValue(7, 1, apply_total >= 36 ? 0 : Math.max(0, 70 - (Math.max(24, arts_text) + Math.max(40, special_text) + (fl1_text + fl2_text + sports_text)))); - data4.setValue(11, 1, Math.max(0, schooling - school_total)); - data4.setValue(12, 1, Math.max(0, 116 - (Math.max(70, apply_total + 40, text_total) + Math.max(schooling, school_total)))); - data4.setValue(14, 1, Math.max(0, (thesis - thesis_total))); - - data5.setValue(1, 1, Math.max(Math.max(0, 70 - text_total), Math.max(0, 40 - special_text))); - data5.setValue(3, 1, Math.max(0, schooling - school_total)); - data5.setValue(4, 1, Math.max(0, 116 - (Math.max(70, apply_total + 40, text_total) + Math.max(schooling, school_total)))); - data5.setValue(6, 1, Math.max(0, (thesis - thesis_total))); - - chart1.draw(data1, options1); - chart2.draw(data2, options2); - chart3.draw(data3, options3); - chart4.draw(data4, options4); - chart5.draw(data5, options5); + // グラフ設定の配列 + const chartConfigs = [ + { dataKey: 'dataUpOuter', elementId: 'donutChartUpOuter', options: options.UpOuter }, + { dataKey: 'dataUpMiddle', elementId: 'donutChartUpMiddle', options: options.UpMiddle }, + { dataKey: 'dataUpInner', elementId: 'donutChartUpInner', options: options.UpInner }, + { dataKey: 'dataDownOuter', elementId: 'donutChartDownOuter', options: options.DownOuter }, + { dataKey: 'dataDownMiddle', elementId: 'donutChartDownMiddle', options: options.DownMiddle } + ]; + + chartConfigs.forEach(({ dataKey, elementId, options }) => { + const data = google.visualization.arrayToDataTable( + [['Category', 'Units']] + .concat(Object.entries(chartData[dataKey]).map(([key, { label, calc }]) => { + const units = calc ? calc.reduce((sum, item) => sum + (chartData.units[item] || 0), 0) : chartData.units[key]; + return [label, units]; + })) + ); + options.colors = Object.values(chartData[dataKey]).map(item => item.color); + new google.visualization.PieChart(document.getElementById(elementId)).draw(data, options); + }); + $('#total_units').text(chartData.units.totalUp); + $('#total_units2').text(chartData.units.totalDown); +} + +function ensureGoogleChartsLoaded(callback) { + if (google && google.visualization && google.visualization.arrayToDataTable) { + callback(); + } else { + google.charts.setOnLoadCallback(callback); } +} - $('#arts1-subjNum').change(rewriteChart); - $('#arts2-subjNum').change(rewriteChart); - $('#arts3-subjNum').change(rewriteChart); - $('#arts1-text').change(rewriteChart); - $('#arts1-school').change(rewriteChart); - $('#arts1-media').change(rewriteChart); - $('#arts2-text').change(rewriteChart); - $('#arts2-school').change(rewriteChart); - $('#arts2-media').change(rewriteChart); - $('#arts3-text').change(rewriteChart); - $('#arts3-school').change(rewriteChart); - $('#arts3-media').change(rewriteChart); - $('#stat-text').change(rewriteChart); - $('#stat-school').change(rewriteChart); - $('#stat-media').change(rewriteChart); - $('#fl1-text').change(rewriteChart); - $('#fl1-school').change(rewriteChart); - $('#fl1-broad').change(rewriteChart); - $('#fl2-text').change(rewriteChart); - $('#fl2-school').change(rewriteChart); - $('#fl2-broad').change(rewriteChart); - $('#sports-text').change(rewriteChart); - $('#sports-school').change(rewriteChart); - $('#required-text').change(rewriteChart); - $('#required-school').change(rewriteChart); - $('#required-media').change(rewriteChart); - $('#elective1-text').change(rewriteChart); - $('#elective1-school').change(rewriteChart); - $('#elective1-media').change(rewriteChart); - $('#elective2-text').change(rewriteChart); - $('#elective2-school').change(rewriteChart); - $('#elective2-media').change(rewriteChart); - $('#thesis-total').change(rewriteChart); - - $('#department').change(rewriteChart); - $('#section').change(rewriteChart); - $('#course').change(rewriteChart); - - $('#apply_stat').change(rewriteChart); - $('#apply_fl1').change(rewriteChart); +// 他の処理から呼び出す場合 +function callDrawChart() { + ensureGoogleChartsLoaded(drawChart); } \ No newline at end of file