ポップアップで色を選択できるようにする ガントチャートをWebアプリとしてつくる(10)で色を選択することができるようになったので、今回は選択した色を反映させます。
⇒ 動作確認はこちらから
ただし削除されては困るのでパスワードをかけています。そのため削除と編集の操作はできません。
バーの表示色を保存する
バーの表示色を保存する処理が必要です。
クライアント側の処理
タスクを編集するページで反映ボタンが押されたらPostするJsonTextを生成するGetResultJsonText関数が実行されます。バーの表示色をDBに保存できるようにするために、この関数を修正します。
template/edit.htmlのscriptタグ内
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
function GetResultJsonText(){ let categoryElements = GetCategoryElements(); let obj = { Tasks : [], PageName : document.getElementById('chart-name').value, }; categoryElements.forEach(categoryElement => { let taskElements = GetTaskElements(categoryElement); let isEmpty = true; taskElements.forEach(taskElement => { isEmpty = false; let task = { TaskName : GetTaskNameFromElement(taskElement), CategoryName : GetCategoryNameFromElement(categoryElement), ManagerName : GetManagerNameFromElement(taskElement), StartDateText: GetStartDateFromElement(taskElement), EndDateText: GetEndDateFromElement(taskElement), Color: GetColorFromElement(taskElement), }; obj.Tasks.push(task); }); // カテゴリにタスクが存在しない場合、CategoryNameだけセットしたオブジェクトを追加する if(isEmpty == true){ let task = { TaskName : '', CategoryName : GetCategoryNameFromElement(categoryElement), ManagerName : '', StartDateText: '', EndDateText: '', Color: '', }; obj.Tasks.push(task); } }); return JSON.stringify(obj); } function GetColorFromElement(element){ for(let i=0; i<element.childElementCount; i++) { if(element.children[i].classList.contains('color')) return element.children[i].style.backgroundColor; } } |
サーバーサイドにおける処理
DBにバーの色も保存しなければならないので、タスク情報を保存するテーブルを作成する関数を修正します。
index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function CreateTaskTable($db, $id){ $taskTableName = GetTaskTableName($id); $text = "CREATE TABLE if not exists {$taskTableName} ("; $text .= "id integer primary key autoincrement,"; $text .= "CategoryName text,"; $text .= "TaskName text,"; $text .= "ManagerName text,"; $text .= "StartDateText text,"; $text .= "EndDateText text,"; $text .= "Color text"; // 追加 $text .= ");"; $sql = $db->prepare($text); $sql->execute(); } |
実際にDBに登録するためのSaveToSqlite関数も修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
function SaveToSqlite($db, $id, $contents){ global $table_pages; foreach ($contents["Tasks"] as $content) { $categoryName = $content["CategoryName"]; $categoryName = EscapeString($categoryName); $taskName = $content["TaskName"]; $taskName = EscapeString($taskName); $managerName = $content["ManagerName"]; $managerName = EscapeString($managerName); $startDateText = $content["StartDateText"]; $endDateText = $content["EndDateText"]; $color = $content["Color"]; // 追加 $taskTableName = GetTaskTableName($id); // カラー情報を登録しなければならないので以下の2行を変更する $sql = $db->prepare("INSERT INTO {$taskTableName} (CategoryName,TaskName,ManagerName,StartDateText,EndDateText,Color) VALUES (?,?,?,?,?,?)"); $sql->execute([$categoryName, $taskName, $managerName, $startDateText, $endDateText, $color]); $sql = null; echo "<br>" . 'a'; } $pageName = EscapeString($contents["PageName"]); $sql = $db->prepare("update {$table_pages} set PageName = '{$pageName}' where id = ${id}"); $sql->execute(); } |
template/page.htmlの{SCRIPT}部分へ挿入するスクリプトを取得する関数も修正が必要です。更新処理をするときにテーブルが作り直されるのですが、古いテーブルの場合、[“Color”]はを取得することができません。そのため処理を切り分ける必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
function GetScriptShowPage($db, $id){ $tableNameTasks = GetTaskTableName($id); $tasks = $db->prepare("SELECT * FROM {$tableNameTasks}"); $tasks->execute(); $result = $tasks->fetchAll(PDO::FETCH_ASSOC); $scriptText = ''; foreach ($result as $row) { $start = $row["StartDateText"]; $end = $row["EndDateText"]; if($start == "") continue; $starts = explode('-', $start); $ends = explode('-', $end); $taskName = $row["TaskName"]; $categoryName = $row["CategoryName"]; $managerName = $row["ManagerName"]; $color = ''; // 古いテーブルの場合、["Color"]は取得できないので処理を切り分ける必要がある if(isset($row["Color"])) $color = $row["Color"]; $scriptText .= "tasks.push(new Task('{$taskName}', '{$categoryName}', '{$managerName}', "; $scriptText .= "{$starts[0]}, {$starts[1]}, {$starts[2]}, "; $scriptText .= "{$ends[0]}, {$ends[1]}, {$ends[2]}"; if($color != '') $scriptText .= ", '{$color}'));"; else $scriptText .= "));"; $scriptText .= "\n"; } return $scriptText; } |
保存したバーの色を反映させる
DBへのデータの登録と取得ができるようになったら新しく読み取ったデータで変更されたバーの色を表示できるようにします。
クライアント側における処理
まずTaskクラスとGanttChartクラスを修正しなければなりません。
js/gantt-chart.js
1 2 3 4 5 6 7 8 9 10 11 |
class Task { // コンストラクタの引数が増えた constructor(taskName, categoryName, managerName, startYear, startMonth, startDay, endYear, endMonth, endDay, color){ this.CategoryName = categoryName; this.TaskName = taskName; this.ManagerName = managerName; this.StartDay = new Date(startYear, startMonth-1, startDay); this.EndDay = new Date(endYear, endMonth-1, endDay); this.Color = color; // 追加 } } |
新しい要素が増えたのでGanttChartクラスのSetSchedules関数、SetSchedule関数、DrawBand関数を修正します。長々と書いているけど修正する部分はわずかです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class GanttChart{ SetSchedules(tasks){ tasks = this.GroupBy(tasks); let prevCategoryName = ''; tasks.forEach(task => { let categoryName = ''; if(prevCategoryName != task.CategoryName){ categoryName = task.CategoryName; prevCategoryName = task.CategoryName; } else categoryName = ''; this.yPos = this.SetSchedule(task.TaskName, categoryName, task.ManagerName, task.StartDay, task.EndDay, this.yPos, task.Color); // 引数が追加されている console.log(task.Color); }); this.DayElements.forEach(element => { element.style.height = this.yPos - 40 + 'px'; }); this.MainElement.style.height = this.yPos + 'px'; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class GanttChart{ SetSchedule(taskName, categoryName, managerName, startDay, endDay, yPos, color){ let startDayText = `${startDay.getFullYear()} / ${this.ZeroPadding(startDay.getMonth()+1,2)} / ${this.ZeroPadding(startDay.getDate(),2)}`; let endDayText = `${endDay.getFullYear()} / ${this.ZeroPadding(endDay.getMonth()+1,2)} / ${this.ZeroPadding(endDay.getDate(),2)}`; let widths =[this.CategoryWidth, this.TaskWidth, this.ManagerWidth, this.PeriodWidth]; let texts =[categoryName, taskName, managerName, startDayText + '<br>' + endDayText]; let newElementMaxHeight = this.SetTexts(texts, widths, yPos); this.DrawBand(startDay, endDay, yPos, newElementMaxHeight, color); // 引数が追加されている return yPos + newElementMaxHeight; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
class GanttChart{ DrawBand(startDay, endDay, yPos, newElementMaxHeight, color){ let ms = new Date(startDay).getTime() - this.GanttChartFirstDay.getTime(); let startpos = Math.round(ms / (1000*60*60*24)); ms = new Date(endDay).getTime()-this.GanttChartFirstDay.getTime(); // 表示する最終日 let endpos = Math.round(ms / (1000*60*60*24)); let newElement1 = document.createElement('div'); newElement1.style.position = 'absolute'; newElement1.style.top = yPos + 'px'; newElement1.style.left = this.ItemsWidth + 'px'; newElement1.style.width = this.TotalWidth - this.ItemsWidth +'px'; newElement1.style.height = '20px'; newElement1.style.borderTop = "solid 1px"; newElement1.style.borderTopColor = '#cccccc'; this.MainElement.appendChild(newElement1); let newElement2 = document.createElement('div'); newElement2.style.position = 'absolute'; newElement2.style.height = '20px'; // 次の行を修正した。colorがundefinedの場合があるので注意。 newElement2.style.backgroundColor = color != undefined ? color : 'rgb(0, 0, 255)'; newElement2.style.top = yPos + (newElementMaxHeight - 20)/2 + 'px'; newElement2.style.fontSize = '12px'; newElement2.style.textAlign = 'left'; if(endpos < startpos){ // 設定が不正 newElement2.style.backgroundColor = 'rgba(255, 0, 0)'; newElement2.style.left = this.ItemsWidth + 'px'; newElement2.style.width = this.DayWidth + this.DayWidth * 5 +'px'; newElement2.innerHTML = ' 設定がおかしい'; newElement2.style.color = '#ffffff'; newElement2.style.textAlign = 'center'; } else if(startpos < 0){ if(endpos < 0){ newElement2.style.width = 0 +'px'; } else if(endpos < this.DayCount){ newElement2.style.left = this.ItemsWidth + 'px'; newElement2.style.width = (this.DayWidth + 1) * (endpos +1) +'px'; } else{ newElement2.style.left = this.ItemsWidth + 'px'; newElement2.style.width = (this.DayWidth + 1) * (this.DayCount) +'px'; } } else if(startpos >= 0 && startpos <= this.DayCount){ if(endpos >= 0 && endpos < this.DayCount){ newElement2.style.left = this.ItemsWidth + (this.DayWidth + 1) * startpos + 'px'; newElement2.style.width = (this.DayWidth + 1) * (endpos - startpos +1) +'px'; } else{ newElement2.style.left = this.ItemsWidth + (this.DayWidth + 1) * startpos + 'px'; newElement2.style.width = (this.DayWidth + 1) * (this.DayCount - startpos) +'px'; } } this.MainElement.appendChild(newElement2); } } |
タスクを編集するページにアクセスしたらバーの表示色が表示されるようになっていなければなりません。
template/edit.htmlのscriptタグ内
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function RebuildingTaskElements(){ let data = document.getElementById('data').innerHTML; document.getElementById('data').innerHTML = ''; console.log(data); let obj = JSON.parse(data); let prevCategoryName = null; let categoryelement = null; obj.forEach(element => { if(prevCategoryName != element.CategoryName){ categoryelement = AddCategory(element.CategoryName); prevCategoryName = element.CategoryName; } if(element.StartDateText != '') AddTask(categoryelement, element.TaskName, element.ManagerName, element.StartDateText, element.EndDateText, element.Color); else console.log('空'); }); console.log('XXXX'); } |
AddTask関数も引数が追加されています。最後の引数がundefinedの時はバーの色は’rgb(0, 0, 255)’です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
function AddTask(categoryElement, taskName, managerName, startText, endText, color){ if(this.parentElement != undefined) categoryElement = this.parentElement; if(taskName == undefined) taskName = '新しいタスク'; if(managerName == undefined) managerName = '担当者'; if(color == undefined) color = 'rgb(0, 0, 255)'; let today = new Date(); let defaultDayText = `${today.getFullYear()}-${ZeroPadding(today.getMonth()+1, 2)}-${ZeroPadding(today.getDate(), 2)}`; if(startText == undefined) startText = defaultDayText; if(endText == undefined) endText = defaultDayText; let newElement = document.createElement('div'); newElement.style.textAlign = 'left'; newElement.style.cursor = 'move'; newElement.style.width = 'auto'; newElement.style.height = 'auto'; newElement.style.fontSize = '14px'; newElement.style.backgroundColor = '#eee8aa'; newElement.style.padding = '10px'; newElement.style.paddingLeft = '30px'; newElement.style.marginTop = '5px'; newElement.style.lineHeight = '24px'; newElement.classList.add('task'); let label = document.createElement('label'); label.innerText = 'タスク名:'; label.style.cursor = 'move'; newElement.appendChild(label); let input = document.createElement('input'); input.type = 'text'; input.value = taskName; input.size = 24; input.classList.add('no-drag'); input.classList.add('task-name'); newElement.appendChild(input); label = document.createElement('label'); label.innerText = '担当者名:'; label.style.cursor = 'move'; label.style.marginLeft = '10px'; newElement.appendChild(label); input = document.createElement('input'); input.type = 'text'; input.value = managerName; input.size = 24; input.classList.add('no-drag'); input.classList.add('manager-name'); newElement.appendChild(input); label = document.createElement('label'); label.innerText = '開始日:'; label.style.cursor = 'move'; label.style.marginLeft = '10px'; newElement.appendChild(label); let start = document.createElement('span'); start.innerText = startText; start.classList.add('no-drag'); start.classList.add('start-date'); start.style.cursor = 'pointer'; newElement.appendChild(start); label = document.createElement('label'); label.innerText = ' 終了日:'; label.style.cursor = 'move'; newElement.appendChild(label); let end = document.createElement('span'); end.innerText = endText; end.classList.add('no-drag'); end.classList.add('end-date'); end.style.cursor = 'pointer'; newElement.appendChild(end); start.addEventListener('click', function(e){ if(curDateElement== null) ShowPopupCalendar(start); }); end.addEventListener('click', function(e){ if(curDateElement== null) ShowPopupCalendar(end); }); buttonElement = document.createElement('button'); buttonElement.innerText = 'タスクの削除'; buttonElement.classList.add('no-drag'); buttonElement.onclick = RemoveTask; buttonElement.style.marginRight = '20px'; buttonElement.style.float = 'right'; newElement.appendChild(buttonElement); label = document.createElement('label'); label.innerText = ' 表示色:'; label.style.cursor = 'move'; newElement.appendChild(label); let selectedColorElement = document.createElement('span'); selectedColorElement.style.marginLeft = '20px'; selectedColorElement.innerText = '----------'; selectedColorElement.classList.add('no-drag'); selectedColorElement.classList.add('color'); selectedColorElement.style.cursor = 'pointer'; selectedColorElement.style.backgroundColor = color; selectedColorElement.style.color = color; selectedColorElement.onclick = SelectedColorClicked; newElement.appendChild(selectedColorElement); categoryElement.appendChild(newElement); } |