はじめに
今となっては古のJSライブラリ
上記ライブラリのスケジュール管理オブジェクトを、いろんな形状で置いてみたので、勘所をメモ書きしておきます。
ニッチな内容だけど、誰かの参考になれば幸いです。
全然、こんなニッチな物、誰も読まないだろうと思ってメモ書きしたら、意外に閲覧数があったので、第2弾です。(根強い人気があるんですかね?)
ソースコードは、前回のカスタマイズ(上記)の反映した上での改修となっています。
色んな形状って?
上記のような、丸、星、シャフトのついた矢印など、様々な図形でスケジュールを引けるように改造しました。
入力データの変更
各データに、type属性を追加して、図形の形を入力データで指示できるように変更します。
{
id: 2, name: "Feature 2", series: [
{ name: "Planned", start: new Date(2010,00,05), end: new Date(2010,00,20), type: "box" },
{ name: "Actual", start: new Date(2010,00,06), end: new Date(2010,00,17), type: "arrow", color: "#F15B55" },
{ name: "Projected", start: new Date(2010,00,06), end: new Date(2010,00,17), type: "box", color: "#e0e0e0" },
{ name: "Projected", start: new Date(2010,00,19), end: new Date(2010,00,19), type: "star", color: "#FFC20E" },
{ name: "Projected", start: new Date(2010,00,21), end: new Date(2010,00,21), type: "circle", color: "#007394" }
]
}
サンプルデータの一部を抜粋してくると、上記のようなイメージです。
追加のスタイルシート
div.ganttview-arrow-cells {
position: relative;
height: 25px;
}
div.ganttview-star-clippath {
position: relative;
width: 25px;
height: 25px;
clip-path: polygon(50% 5%, 61% 40%, 98% 40%, 68% 62%, 79% 96%, 50% 75%, 21% 96%, 32% 62%, 2% 40%, 39% 40%);
}
div.ganttview-circle-clippath {
position: relative;
width: 25px;
height: 25px;
clip-path: circle(41% at 50% 50%);
}
div.ganttview-arrow-cell-clippath {
position: absolute;
height: 25px;
clip-path: polygon(0 33%, 100% 33%, 100% 67%, 0 67%);
}
div.ganttview-arrow-triangle-cell-clippath {
position: absolute;
width: 25px;
height: 25px;
clip-path: polygon(0 0, 100% 50%, 0 100%, 30% 50%);
}
div.ganttview-arrow-circle-cell-clippath {
position: absolute;
width: 25px;
height: 25px;
clip-path: circle(41% at 50% 50%);
}
div.ganttview-star-cell-clippath {
position: absolute;
width: 25px;
height: 25px;
clip-path: polygon(50% 5%, 61% 40%, 98% 40%, 68% 62%, 79% 96%, 50% 75%, 21% 96%, 32% 62%, 2% 40%, 39% 40%);
}
div.ganttview-circle-cell-clippath {
position: absolute;
width: 25px;
height: 25px;
clip-path: circle(41% at 50% 50%);
}
clip-path を使って、いろんな図形を作るというのは、他にも記事をアップしてる方がいますので、jquery.ganttViewのカスタムの方に焦点を当てて、clip-pathに深くは触れません。
改修ポイント編(javascript)
前回、手をいれた「addBlocks」を、更に改造していきます。
addBlocks :管理オブジェクト描画の全体制御
function addBlocks(div, data, cellWidth, start) {
// ~省略
// 入力データのループ
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].series.length; j++) {
var series = data[i].series[j];
if("複数オブジェクトのキー" in series && series."複数オブジェクトのキー".length > 0){
var tasks;
tasks = jQuery("<div>", {
"class": "ganttview-block-cells"
});
rowIdx = addRowDataForTasks(div, tasks, data[i], series."複数オブジェクトのキー", cellWidth, start, rows, rowIdx);
} else {
rowIdx = addRowData(div, data[i], series, cellWidth, start, rows, rowIdx);
}
}
}
}
スケジュール管理オブジェクトを置くところは、全部、関数に切り出してしまいます。
1行に1管理オブジェクトを設置するようの関数(元々)
ですが、、、矢印型は、1行複数オブジェクト(丸型と箱型とシャフト型の組み合わせ)なので専用関数を呼び出します。
addRowData : 1行データの描画
function addRowData(div, series, data, cellWidth, start, rows, rowIdx) {
var styleName = judgeDisplayStyleType(data, false);
var obj;
if(CHART_TYPE.ARROW == data.type){
var arrowObjs = jQuery("<div>", {
"class": "ganttview-arrow-cells"
});
obj = getArrowBlock(div, series, data, cellWidth, start, rows, styleName, arrowObjs);
} else {
obj = getEachBlock(div, series, data, cellWidth, start, rows, styleName, false);
}
jQuery(rows[rowIdx]).append(obj);
rowIdx = rowIdx + 1;
return rowIdx;
}
こっちは、第1段で改造した、1行に複数の管理オブジェクトを設置する関数です。
addRowDataForTasks 1行に複数タスクを描画する用の関数
function addRowDataForTasks(div, tasks, series, taskList, cellWidth, start, rows, rowIdx) {
for(var i = 0; i < taskList.length; i++){
var data = taskList[i];
var styleName = judgeDisplayStyleType(data, true);
if(CHART_TYPE.ARROW == data.type){
tasks = getArrowBlock(div, series, data, cellWidth, start, rows, styleName, tasks);
}else{
var blockObj = getEachBlock(div, series, data, cellWidth, start, rows, styleName, false);
tasks.append(blockObj);
}
}
jQuery(rows[rowIdx]).append(tasks);
rowIdx = rowIdx + 1;
return rowIdx;
}
こちらでも矢印型は、(丸型と箱型とシャフト型の組み合わせ)なので専用関数を呼び出します。
judgeDisplayStyleType 図形毎の専用スタイルシート呼び分け
function judgeDisplayStyleType(data, multiObjectsFlag) {
// デフォルト宣言
var styleName = "ganttview-block";
if(multiObjectsFlag){
styleName = "ganttview-block-cell";
}
// 引き渡された指定値で表示する形状を変更
if("type" in data && data.type){
if(multiObjectsFlag){
// 1行内に複数の管理オブジェクトを配置
if(CHART_TYPE.BOX == data.type){
styleName = "ganttview-block-cell";
} else if(CHART_TYPE.ARROW == data.type){
styleName = "ganttview-arrow-cell-clippath";
} else if(CHART_TYPE.STAR == data.type){
styleName = "ganttview-star-cell-clippath";
} else if(CHART_TYPE.CIRCLE == data.type){
styleName = "ganttview-circle-cell-clippath";
}
}else{
// 1行内に1行の管理オブジェクトを配置
if(CHART_TYPE.BOX == data.type){
styleName = "ganttview-block";
} else if(CHART_TYPE.ARROW == data.type){
// 矢印型は複数オブジェクト前提のため cell付きのスタイルを利用する
styleName = "ganttview-arrow-cell-clippath";
} else if(CHART_TYPE.STAR == data.type){
styleName = "ganttview-star-clippath";
} else if(CHART_TYPE.CIRCLE == data.type){
styleName = "ganttview-circle-clippath";
}
}
}
return styleName;
}
addRowDataとaddRowDataForTasksの関数で、それぞれの図形に合わせたスタイルシートを取得している為、追加したスタイルシートの、どれを利用するかサンプルデータの中の図形の指定でスタイルシートを切り替えます。
getArrowBlock 矢印型を描画するには、3つのオブジェクト(丸型・箱型・シャフト型)がいるので特殊処理を実装
function getArrowBlock(div, series, data, cellWidth, startPlanDate, rows, styleName, objs) {
var startPointObj = Object.create(data);
var endPointObj = Object.create(data);
// 補正用に開始日・終了日を退避する
startPointObj['arrow_start'] = data.start;
startPointObj['arrow_end'] = data.end;
// 開始日基準で終了日を上書きする
startPointObj.end = data.start;
// 補正用に開始日・終了日を退避する
startPointObj['arrow_start'] = data.start;
startPointObj['arrow_end'] = data.end;
// 終了日基準で開始日を上書きする
endPointObj.start = data.end;
// 強制的に丸型の箱をオブジェクトを用意する
var startPontBlock = getEachBlock(div, series, startPointObj, cellWidth, startPlanDate, rows, "ganttview-arrow-circle-cell-clippath", true);
// 矢印型を用意する
var arrowObjBlock = getEachBlock(div, series, data, cellWidth, startPlanDate, rows, styleName, false);
// 強制的に終端の矢印箱オブジェクトを用意する
var endPointBlock = getEachBlock(div, series, endPointObj, cellWidth, startPlanDate, rows, "ganttview-arrow-triangle-cell-clippath", true);
objs.append(startPontBlock);
objs.append(arrowObjBlock);
objs.append(endPointBlock);
return objs;
}
描画しようとしてるデータのディープコピーを作って、開始日・終了日を騙して、始点(丸型)と終点(シャフト型)を描画するようにして、組み合わせて矢印に見えるようにしています。
getEachBlock 各種図形の位置決め、微調整、描画
function getEachBlock(div, series, data, cellWidth, start, rows, styleName, camouflageDateFlag) {
var size = DateUtils.daysBetween(data.start, data.end ) + 1;
var offset = DateUtils.daysBetween(start, data.start);
// 初期化
var widthVal = 0;
var marginLeftVal = 0;
widthVal = ((size * cellWidth) - 5);
marginLeftVal = (offset * cellWidth) + 1;
// 丸型と星型の時は、正方形になるように幅を調整する
if(CHART_TYPE.STAR == data.type || CHART_TYPE.CIRCLE == data.type){
widthVal = 25;
}
// 矢印型で始点・終点用の箱を用意する時は微調整する
if(CHART_TYPE.ARROW == data.type && camouflageDateFlag){
widthVal = 25;
var originArrowSize = DateUtils.daysBetween(data.arrow_start, data.arrow_end) + 1;
size = originArrowSize;
}
// 矢印型の時で真ん中の箱は左横のマージンと横幅を微調整
if(CHART_TYPE.ARROW == data.type && ! camouflageDateFlag){
widthVal = widthVal - 5;
marginLeftVal = marginLeftVal + 7;
}
let title = data.name ;
var block = jQuery("<div>", {
"title": title + ", " + size + " 日間",
"class": styleName,
"css": {
"width": widthVal + "px",
"margin-left": marginLeftVal + "px",
"left" : "0px",
"right" : "0px",
}
});
// 背景色指定をデータで受け取る
if("color" in data && data.color){
block.css("background-color", data.color);
}
if(CHART_TYPE.BOX == data.box){
block.append(jQuery("<div>", { "class": "ganttview-block-text" }).text(size));
}
addBlockData(block, data, series);
return block;
}
既存の jquery.gannttViewの箱型を描画する為の処理が色濃く残ってるのが、この関数ですね。
図形によって、微調整(矢印型の重ね合わせ位置の調整、星型・丸型の縦幅・横幅の均一化)をしています。