Index: arms/html/analysisTime/content-container.html =================================================================== diff -u -r2336fb82023d754e60264b4fd07b30c9d9efe5e5 -r76a367fb3ee0cf801114583cb698a7534fc2083b --- arms/html/analysisTime/content-container.html (.../content-container.html) (revision 2336fb82023d754e60264b4fd07b30c9d9efe5e5) +++ arms/html/analysisTime/content-container.html (.../content-container.html) (revision 76a367fb3ee0cf801114583cb698a7534fc2083b) @@ -694,22 +694,17 @@
-
+

- 요구사항 및 연결된 이슈 분포 + 요구사항 현황 차트

-
-
- - -
-
+
@@ -718,19 +713,19 @@

- 요구사항 및 연결된 이슈 업데이트 날짜 현황 + 일자별 누적 업데이트 현황

@@ -1000,4 +995,11 @@ height: 100%; overflow: visible; } + + #candlestick-chart-container { + position: relative; + width: 100%; + height: 100%; + overflow: visible; + } \ No newline at end of file Index: arms/js/analysisScope.js =================================================================== diff -u -r3373387f07025639254a07fd90d2c2909554a84d -r76a367fb3ee0cf801114583cb698a7534fc2083b --- arms/js/analysisScope.js (.../analysisScope.js) (revision 3373387f07025639254a07fd90d2c2909554a84d) +++ arms/js/analysisScope.js (.../analysisScope.js) (revision 76a367fb3ee0cf801114583cb698a7534fc2083b) @@ -14,13 +14,14 @@ "../reference/light-blue/lib/vendor/http_blueimp.github.io_JavaScript-Load-Image_js_load-image.js", "../reference/light-blue/lib/vendor/http_blueimp.github.io_JavaScript-Canvas-to-Blob_js_canvas-to-blob.js", "../reference/light-blue/lib/jquery.iframe-transport.js", - // network chart - "./js/analysisTime/d3.v5.min.js", + "./js/common/colorPalette.js", // donut chart "../reference/jquery-plugins/c3/c3.min.css", "../reference/jquery-plugins/c3/c3-custom.css", "../reference/jquery-plugins/c3/c3.min.js", - "./js/common/colorPalette.js", + // network chart + "./js/analysisTime/d3.v5.min.js", + ], [ "../reference/lightblue4/docs/lib/slimScroll/jquery.slimscroll.min.js", @@ -200,6 +201,10 @@ selectedVersionId = pdServiceVersionIds.join(','); statisticsMonitor($("#selected_pdService").val(), selectedVersionId); + + donutChart($("#selected_pdService").val(), selectedVersionId); + combinationChart($("#selected_pdService").val(), selectedVersionId); + getRelationJiraIssueByPdServiceAndVersions($("#selected_pdService").val(), selectedVersionId); if (data.length > 0) { Index: arms/js/analysisTime.js =================================================================== diff -u -r2336fb82023d754e60264b4fd07b30c9d9efe5e5 -r76a367fb3ee0cf801114583cb698a7534fc2083b --- arms/js/analysisTime.js (.../analysisTime.js) (revision 2336fb82023d754e60264b4fd07b30c9d9efe5e5) +++ arms/js/analysisTime.js (.../analysisTime.js) (revision 76a367fb3ee0cf801114583cb698a7534fc2083b) @@ -22,7 +22,6 @@ // chart Colors // "./js/dashboard/chart/colorPalette.js", // 2번째 박스 d3 게이지 차트 - // "../reference/jquery-plugins/d3-v4.13.0/d3.v4.min.js", "../reference/jquery-plugins/c3/c3.min.css", "../reference/jquery-plugins/c3/c3-custom.css", "../reference/jquery-plugins/c3/c3.min.js", @@ -32,33 +31,11 @@ "../reference/jquery-plugins/info-chart-v1/js/timeline_analysisTime.js", //"./js/dashboard/chart/timeline_custom.js", "./js/dashboard/chart/infographic_custom.css", - // 네번째 박스 차트 - // d3.v2와 d3.v4 버전차이 오류생김... - // "../reference/light-blue/lib/nvd3/lib/d3.v2.js", - // "../reference/light-blue/lib/nvd3/nv.d3.custom.js", - // "../reference/light-blue/lib/nvd3/src/core.js", - // "../reference/light-blue/lib/nvd3/src/models/pieChartTotal.js", - // "../reference/light-blue/lib/nvd3/src/models/pie.js", - // "../reference/light-blue/lib/nvd3/src/models/legend.js", - // "../reference/light-blue/lib/nvd3/src/models/multiBar.js", - // "../reference/light-blue/lib/nvd3/src/models/multiBarChart.js", - // "./js/analysisTime/stats.js", - // "../reference/light-blue/lib/nvd3/src/models/axis.js", - // "../reference/light-blue/lib/nvd3/src/utils.js", - // "../reference/light-blue/lib/nvd3/stream_layers.js", - // 6번째 박스 timeline - //"https://code.jquery.com/jquery-3.2.1.slim.min.js", - //"https://cdnjs.cloudflare.com/ajax/libs/raphael/2.2.7/raphael.min.js", "../reference/jquery-plugins/Timeline-Graphs-jQuery-Raphael/timeline/css/newtimeline.css", "../reference/jquery-plugins/Timeline-Graphs-jQuery-Raphael/timeline/js/raphael.min.js", "../reference/jquery-plugins/Timeline-Graphs-jQuery-Raphael/timeline/js/newtimeline.js", - //"../reference/jquery-plugins/Timeline-Graphs-jQuery-Raphael/js/newdemo.js", // 3번째 박스 데이터 테이블 내 차트 - // "../reference/light-blue/lib/sparkline/jquery.sparkline.js", "../reference/jquery-plugins/echarts-5.4.3/dist/echarts.min.js", - /*"../reference/jquery-plugins/echarts-5.4.3/test/lib/simpleRequire.js", - "../reference/jquery-plugins/echarts-5.4.3/test/lib/config.js",*/ - // "./js/analysisTime/index.js", // 5번째 박스 network chart "./js/analysisTime/d3.v5.min.js", // 5번째 박스 heatmap @@ -120,6 +97,7 @@ //버전 멀티 셀렉트 박스 이니시에이터 makeVersionMultiSelectBox(); + candleStickChart(); dashboardColor = dashboardPalette.dashboardPalette01; }) @@ -180,20 +158,61 @@ // endPointUrl = "/T_ARMS_REQSTATUS_" + $("#selected_pdService").val() + "/getStatusMonitor.do?disable=false"; // } - //이슈리스트 진행 상황 - //getIssueStatus($("#selected_pdService").val(), endPointUrl); - //통계로드 - //statisticsLoad($("#selected_pdService").val(), null); console.log("선택된 제품(서비스) c_id = " + $("#selected_pdService").val()); - //타임라인 - // $("#notifyNoVersion2").hide(); - - // 투입 인력별 요구사항 차트 - // dataTableLoad($("#selected_pdService").val(), endPointUrl); }); } // end makePdServiceSelectBox() +function bind_VersionData_By_PdService() { + $(".multiple-select option").remove(); + $.ajax({ + url: "/auth-user/api/arms/pdService/getVersionList.do?c_id=" + $("#selected_pdService").val(), + type: "GET", + dataType: "json", + progress: true, + statusCode: { + 200: function (data) { + ////////////////////////////////////////////////////////// + // console.log(data.response); // versionData + + versionListData = data.response.reduce((obj, item) => { + obj[item.c_id] = item; + return obj; + }, {}); + + var pdServiceVersionIds = []; + for (var k in data.response) { + var obj = data.response[k]; + pdServiceVersionIds.push(obj.c_id); + var newOption = new Option(obj.c_title, obj.c_id, true, false); + $(".multiple-select").append(newOption); + } + + selectedVersionId = pdServiceVersionIds.join(','); + + statisticsMonitor($("#selected_pdService").val(), selectedVersionId); + + showStatusesCountBox(); + getReqLinkedIssueCountAndRate($("#selected_pdService").val(), selectedVersionId, true); + getReqLinkedIssueCountAndRate($("#selected_pdService").val(), selectedVersionId, false); + + combinationChart($("#selected_pdService").val(), selectedVersionId); + + getRelationJiraIssueByPdServiceAndVersions($("#selected_pdService").val(), selectedVersionId); + calendarHeatMap($("#selected_pdService").val(), selectedVersionId); + + if (data.length > 0) { + console.log("display 재설정."); + } + //$('#multiversion').multipleSelect('refresh'); + //$('#edit_multi_version').multipleSelect('refresh'); + $(".multiple-select").multipleSelect("refresh"); + ////////////////////////////////////////////////////////// + } + } + }); +} + //////////////////// //버전 멀티 셀렉트 박스 //////////////////// @@ -239,6 +258,16 @@ }); } +function formatDate(date) { + var year = date.getFullYear(); + var month = (date.getMonth() + 1).toString().padStart(2, "0"); + var day = date.getDate().toString().padStart(2, "0"); + return year + "-" + month + "-" + day; +} + +//////////////////// +// 첫번째 박스 +//////////////////// function showStatusesCountBox() { $("#progress_req_status").slimScroll({ height: "190px", @@ -260,35 +289,7 @@ disableFadeOut: false }); } -function getRelationJiraIssueByPdServiceAndVersions(pdServiceLink, pdServiceVersions) { - $.ajax({ - url: "/auth-user/api/arms/analysis/time/pdService/pdServiceVersions", - type: "GET", - data: {"pdServiceLink": pdServiceLink, "pdServiceVersionLinks": pdServiceVersions}, - contentType: "application/json;charset=UTF-8", - dataType: "json", - progress: true, - async: true, - statusCode: { - 200: function (data) { - // 버전 선택 시 데이터 파싱 - - statusTimeline(data); - sevenTimeline(data); - - scatterChart(data); - // setTimeout(function () { - // networkChart(pdServiceVersions, data); - // },1000); - - globalJiraIssue = data; - - } - } - }); - -} function statisticsMonitor(pdservice_id, pdservice_version_id) { console.log("선택된 서비스 ===> " + pdservice_id); console.log("선택된 버전 리스트 ===> " + pdservice_version_id); @@ -356,13 +357,13 @@ var daysCount = lastDay.getDate(); // 오늘 일자 구하기 var day = today.getDate(); - var today_flag = { + var today_flag = { "title" : "오늘", "startDate" : formatDate(firstDay), "endDate" : formatDate(lastDay), "id" : "today_flag" - }; - versionTimeline.push(today_flag); + }; + versionTimeline.push(today_flag); $("#version-timeline-bar").show(); Timeline.init($("#version-timeline-bar"), versionTimeline); @@ -385,367 +386,8 @@ } } }); - - - } -function formatDate(date) { - var year = date.getFullYear(); - var month = (date.getMonth() + 1).toString().padStart(2, "0"); - var day = date.getDate().toString().padStart(2, "0"); - return year + "-" + month + "-" + day; -} -function bind_VersionData_By_PdService() { - $(".multiple-select option").remove(); - $.ajax({ - url: "/auth-user/api/arms/pdService/getVersionList.do?c_id=" + $("#selected_pdService").val(), - type: "GET", - dataType: "json", - progress: true, - statusCode: { - 200: function (data) { - ////////////////////////////////////////////////////////// - // console.log(data.response); // versionData - - versionListData = data.response.reduce((obj, item) => { - obj[item.c_id] = item; - return obj; - }, {}); - - var pdServiceVersionIds = []; - for (var k in data.response) { - var obj = data.response[k]; - pdServiceVersionIds.push(obj.c_id); - var newOption = new Option(obj.c_title, obj.c_id, true, false); - $(".multiple-select").append(newOption); - } - - selectedVersionId = pdServiceVersionIds.join(','); - - statisticsMonitor($("#selected_pdService").val(), selectedVersionId); - - showStatusesCountBox(); - getReqLinkedIssueCountAndRate($("#selected_pdService").val(), selectedVersionId, true); - getReqLinkedIssueCountAndRate($("#selected_pdService").val(), selectedVersionId, false); - - combinationChart($("#selected_pdService").val(), selectedVersionId); - - getRelationJiraIssueByPdServiceAndVersions($("#selected_pdService").val(), selectedVersionId); - calendarHeatMap($("#selected_pdService").val(), selectedVersionId); - - if (data.length > 0) { - console.log("display 재설정."); - } - //$('#multiversion').multipleSelect('refresh'); - //$('#edit_multi_version').multipleSelect('refresh'); - $(".multiple-select").multipleSelect("refresh"); - ////////////////////////////////////////////////////////// - } - } - }); -} - -// 데이터 테이블 구성 이후 꼭 구현해야 할 메소드 : 열 클릭시 이벤트 -function dataTableClick(tempDataTable, selectedData) { - console.log(selectedData); -} - -//데이터 테이블 그리고 난 후 시퀀스 이벤트 -function dataTableCallBack(settings, json) { - console.log("check"); -} - -//데이터 테이블 그리고 난 후 시퀀스 이벤트 -function dataTableDrawCallback(tableInfo) { - /*$("#" + tableInfo.sInstance) - .DataTable() - .columns.adjust() - .responsive.recalc();*/ -} - -// -------------------- 데이터 테이블을 만드는 템플릿으로 쓰기에 적당하게 리팩토링 함. ------------------ // -function dataTableLoad(selectId, endPointUrl) { - var columnList = [ - { name: "c_pdservice_link", title: "제품(서비스) 아이디", data: "c_pdservice_link", visible: false }, - { - name: "c_pdservice_name", - title: "제품(서비스)", - data: "c_pdservice_name", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + getStrLimit(data, 25) + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { name: "c_pds_version_link", title: "제품(서비스) 버전 아이디", data: "c_pds_version_link", visible: false }, - { - name: "c_pds_version_name", - title: "제품(서비스) 버전", - data: "c_pds_version_name", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + data + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { name: "c_req_link", title: "요구사항 아이디", data: "c_req_link", visible: false }, - { name: "c_issue_url", title: "요구사항 이슈 주소", data: "c_issue_url", visible: false }, - { - name: "c_req_name", - title: "요구사항", - data: "c_req_name", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + data + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { name: "c_jira_server_link", title: "지라 서버 아이디", data: "c_jira_server_link", visible: false }, - { name: "c_jira_server_url", title: "지라 서버 주소", data: "c_jira_server_url", visible: false }, - { - name: "c_jira_server_name", - title: "JIRA 서버명", - data: "c_jira_project_name", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + data + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { name: "c_jira_project_link", title: "지라 프로젝트 아이디", data: "c_jira_project_link", visible: false }, - { name: "c_jira_project_url", title: "지라 프로젝트 주소", data: "c_jira_project_url", visible: false }, - { - name: "c_jira_project_name", - title: "JIRA 프로젝트명", - data: "c_jira_project_name", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + data + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { - name: "c_jira_project_key", - title: "JIRA 프로젝트키", - data: "c_jira_project_key", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + data + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { - name: "c_issue_key", - title: "요구사항 이슈 키", - data: "c_issue_key", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - var _render = - '
' + data + - '"+ - "
"; - return _render; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { name: "c_issue_priority_link", title: "요구사항 이슈 우선순위 아이디", data: "c_issue_priority_link", visible: false }, - { - name: "c_issue_priority_name", - title: "요구사항 이슈 우선순위", - data: "c_issue_priority_name", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + data + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { name: "c_issue_status_link", title: "요구사항 이슈 상태 아이디", data: "c_issue_status_link", visible: false }, - { - name: "c_issue_status_name", - title: "요구사항 이슈 상태", - data: "c_issue_status_name", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + data + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { name: "c_issue_resolution_link", title: "요구사항 이슈 해결책 아이디", data: "c_issue_resolution_link", visible: false }, - { - name: "c_issue_resolution_name", - title: "요구사항 이슈 해결책", - data: "c_issue_resolution_name", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + data + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { - name: "c_issue_reporter", - title: "요구사항 이슈 보고자", - data: "c_issue_reporter", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + data + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { - name: "c_issue_assignee", - title: "요구사항 이슈 할당자", - data: "c_issue_assignee", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + data + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { - name: "c_issue_create_date", - title: "요구사항 이슈 생성일자", - data: "c_issue_create_date", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + dateFormat(data) + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - }, - { - name: "c_issue_update_date", - title: "요구사항 이슈 최근 업데이트 일자", - data: "c_issue_update_date", - render: function (data, type, row, meta) { - if (isEmpty(data) || data === "unknown") { - return "
N/A
"; - } else { - return "
" + dateFormat(data) + "
"; - } - return data; - }, - className: "dt-body-left", - visible: true - } - ]; - var rowsGroupList = [1,3,6]; - var columnDefList = [ - { - orderable: false, - className: "select-checkbox", - targets: 0 - } - ]; - var orderList = [[1, "asc"]]; - var jquerySelector = "#reqstatustable"; - var ajaxUrl = "/auth-user/api/arms/reqStatus" + endPointUrl; - var jsonRoot = ""; - var buttonList = [ - "copy", - "excel", - "print", - { - extend: "csv", - text: "Export csv", - charset: "utf-8", - extension: ".csv", - fieldSeparator: ",", - fieldBoundary: "", - bom: true - }, - { - extend: "pdfHtml5", - orientation: "landscape", - pageSize: "LEGAL" - } - ]; - var selectList = {}; - var isServerSide = false; - - reqStatusDataTable = dataTable_build( - jquerySelector, - ajaxUrl, - jsonRoot, - columnList, - rowsGroupList, - columnDefList, - selectList, - orderList, - buttonList, - isServerSide - ); -} -// -------------------- 데이터 테이블을 만드는 템플릿으로 쓰기에 적당하게 리팩토링 함. ------------------ // - -//////////////////// -// 첫번째 박스 -//////////////////// - function calculateDateDiff(date1, date2) { return Math.floor((new Date(date1) - new Date(date2)) / (1000 * 60 * 60 * 24)); } @@ -813,17 +455,6 @@ $("#" + progressId).append(html_piece); }); $("#" + totalId).text(totalCount); - - /*$("#" + completedId).text(completedCount + " 개"); - - - var completion = 0; - if (totalCount !== 0 ) { - completion = ((completedCount/totalCount) * 100).toFixed(0); - } - - $("#" + rateId).text(completion + "%").css("width", completion +"%");*/ - } //////////////////// @@ -922,8 +553,6 @@ .outerRadius(radius * 0.9); var totalDate; - var startDDay; - var endDDay; numSections = data.length; // 전체 색션의 수(버전의 수) sectionPerc = 1 / numSections / 2; // '/ 2' for Half-circle @@ -965,25 +594,19 @@ $("#endDDay").css("color", ""); if(diffStart > 0) { - console.log("시작일은 오늘보다 이전입니다."); $("#startDDay").text("D + " + diffStart); } else if(diffStart === 0) { - console.log("오늘은 시작일입니다."); $("#startDDay").text("D - day"); } else { - console.log("시작일은 오늘보다 이후입니다."); diffStart *= -1; $("#startDDay").text("D - " + diffStart); } if(diffEnd > 0) { - console.log("종료일은 오늘보다 이전입니다."); $("#endDDay").css("color", "#FF4D4D").css("font-weight", "bold").text("D + " + (diffEnd)).append(" 초과"); } else if(diffEnd === 0) { - console.log("오늘은 종료일입니다."); $("#endDDay").text("D - day"); } else { - console.log("종료일은 오늘보다 이후입니다."); diffEnd *= (-1); $("#endDDay").text("D - " + diffEnd); } @@ -1145,134 +768,175 @@ //////////////////// // 세번째 박스 //////////////////// -/* -function radarChart(pdServiceId, pdServiceVersionList) { +function scatterChart(data) { + console.log(data); + var requirementDataCount = {}; + var relationIssueDataCount = {}; - var maxCount; - var versionText = []; - var reqCount = []; + data.forEach(jiraissue => { + if(jiraissue.updated === null || jiraissue.updated === undefined) { + return; + } - var _url = "/auth-user/api/arms/dashboard/normal/"+pdServiceId; - $.ajax({ - url: _url, - type: "GET", - data: { "서비스아이디" : pdServiceId, - "메인그룹필드" : "pdServiceVersion", - "isReq" : true, - "컨텐츠보기여부" : false, - "크기" : 1000 - }, - contentType: "application/json;charset=UTF-8", - dataType: "json", - progress: true, - async: false, - statusCode: { - 200: function (data) { - maxCount = data.전체합계; - var result = data.검색결과.group_by_pdServiceVersion; + var updatedDate = jiraissue.updated.split('T')[0]; + // var updatedDate = jiraissue.updated; - result.forEach(item => { - if (versionListData[item.필드명]) { - versionListData[item.필드명].totalCount = item.개수; - } - }); - - Object.values(versionListData).forEach(item => { - var version = {}; - version.text = item.c_title; - version.max = maxCount; - - versionText.push(version); - reqCount.push(item.totalCount); - }); + if (jiraissue.isReq === true) { + if (!requirementDataCount[updatedDate]) { + requirementDataCount[updatedDate] = 0; } + requirementDataCount[updatedDate]++; + } else { + if (!relationIssueDataCount[updatedDate]) { + relationIssueDataCount[updatedDate] = 0; + } + relationIssueDataCount[updatedDate]++; } }); - var chart = echarts.init(document.getElementById('radar-chart-main')); + var requirementData = Object.keys(requirementDataCount).map(key => { + var dateObj = new Date(key+'T00:00:00'); + return [dateObj, requirementDataCount[key]]; + }); - chart.setOption({ - color: ['#E49400'], - dataZoom: [ - { // The first dataZoom component - radiusAxisIndex: [0, 2] // Indicates that this dataZoom component - // controls the first and the third radiusAxis - } - ], - aria: { - show: false - }, - tooltip: {}, - legend: { - data: [{ - icon: 'circle', - name: '요구사항' - }], - textStyle: { - color: 'white', // 원하는 텍스트 색상으로 변경합니다. - fontSize: 14 - } - }, - radar: { - radius: [0, '50%'], - triggerEvent: true, - // shape: 'circle', - indicator: versionText, - name: { - rotate: 45, // 텍스트를 45도로 회전시킵니다. - position: 'outside', // 텍스트를 레이더 영역 내부에 위치시킵니다. - color: '#ffffff', - formatter: function(text) { - // 줄바꿈을 위해 '\n' 문자를 삽입합니다. - var wrappedValue = text.replace(/(.{12})/g, '$1\n'); // 10자마다 줄바꿈 - return '[' + wrappedValue + ']'; - }, - rich: { - value: { - align: 'left', - color: '#ffffff', - lineHeight: 10 // 줄 간격을 설정합니다. + var relationIssueData = Object.keys(relationIssueDataCount).map(key => { + var dateObj = new Date(key+'T00:00:00'); + return [dateObj, relationIssueDataCount[key]]; + }); + + + var dom = document.getElementById('scatter-chart-container'); + + var myChart = echarts.init(dom, 'dark', { + renderer: 'canvas', + useDirtyRect: false + }); + var app = {}; + + var option; + + if ((requirementData && requirementData.length > 0) || (relationIssueData && relationIssueData.length > 0) ) { + + option = { + aria: { + show: true + }, + legend: { + data: ['요구사항' , '연결된 이슈'] // 여기에 실제 데이터 종류를 적어주세요 + }, + /* toolbox: { + left: 'left', + feature: { + dataView: {}, + saveAsImage: {}, + dataZoom: {} + } + },*/ + xAxis: { + type: 'time', + splitLine: { + show: true, + lineStyle: { + color: 'rgba(255,255,255,0.2)', // 라인 색상을 빨간색으로 변경 + width: 1, // 라인 너비를 2로 변경 + type: 'solid' // 라인 유형을 실선으로 변경 } } - } - }, - series: [{ - name: '', - type: 'radar', - label: { - normal: { + }, + yAxis: { + type: 'value', + splitLine: { show: true, - textStyle: { - color: 'white' // 원하는 텍스트 색상으로 변경합니다. + lineStyle: { + color: 'rgba(255,255,255,0.2)', // 라인 색상을 빨간색으로 변경 + width: 1, // 라인 너비를 2로 변경 + type: 'solid' // 라인 유형을 실선으로 변경 } } }, - itemStyle: { - borderWidth: 2, - borderColor: '#fff' - }, - // areaStyle: {normal: {}}, - data : [ + series: [ { - value: reqCount, - name: '요구사항' + name: '요구사항', + data: requirementData, + type: 'scatter', + symbol: 'diamond', + clip: false, // clip 옵션 추가 + label: { + emphasis: { + show: true, + color: '#FFFFFF' + } + }, + symbolSize: function (val) { + var sbSize = 10; + if (val[1] > 10) { + sbSize = val[1] * 1.1; + } + return sbSize; + }, + }, + { + name: '연결된 이슈', + data: relationIssueData, + type: 'scatter', + clip: false, // clip 옵션 추가 + label: { + emphasis: { + show: true + } + }, + symbolSize: function (val) { + var sbSize = 10; + if (val[1] > 10) { + sbSize = val[1] * 1.1; + } + return sbSize; + }, + itemStyle: { + color: '#13de57' + }, } ], - symbol: 'circle', - symbolSize: 7, - symbolRotate: function(value, params) { - return ~~(360 * Math.random()); + tooltip: { + trigger: 'axis', + position: 'top', + borderWidth: 1, + axisPointer: { + type: 'cross' + } + }, + backgroundColor: 'rgba(255,255,255,0)', + animationDelay: function (idx) { + return idx * 20; + }, + animationDelayUpdate: function (idx) { + return idx * 20; } - } - ] - }); - window.addEventListener('resize', function () { - chart.resize(); - }); -} -*/ + }; + myChart.on('click', function (params) { + console.log(params.data); + }); + } + else { + option = { + title: { + text: '데이터가 없습니다', + left: 'center', + top: 'middle' + }, + backgroundColor: 'rgba(255,255,255,0)', + }; + } + + if (option && typeof option === 'object') { + myChart.setOption(option, true); + } + + window.addEventListener('resize', myChart.resize); +} + // 바차트 function combinationChart(pdServiceLink, pdServiceVersionLinks) { function combinationChartNoData() { @@ -1442,295 +1106,31 @@ } //////////////////// -// 다섯번째 박스 +// 네번째 박스 //////////////////// -/*function networkChart(pdServiceVersions, jiraIssueData) { - d3.select(".network-graph").selectAll("*").remove(); - var NETWORK_DATA = { - "nodes": [], - "links": [] - }; +function getRelationJiraIssueByPdServiceAndVersions(pdServiceLink, pdServiceVersions) { + $.ajax({ + url: "/auth-user/api/arms/analysis/time/pdService/pdServiceVersions", + type: "GET", + data: {"pdServiceLink": pdServiceLink, "pdServiceVersionLinks": pdServiceVersions}, + contentType: "application/json;charset=UTF-8", + dataType: "json", + progress: true, + async: true, + statusCode: { + 200: function (data) { + console.log(data); + statusTimeline(data); + sevenTimeline(data); + scatterChart(data); - pdServiceData.id = pdServiceData.c_id; - pdServiceData.type = "pdService"; - NETWORK_DATA.nodes.push(pdServiceData); + globalJiraIssue = data; - var targetIds = pdServiceVersions.split(',').map(Number); - var versionList = pdServiceData.pdServiceVersionEntities; - - versionList.forEach((item)=> { - if (targetIds.includes(item.c_id)) { - item.id = item.c_id; - item.type = "version"; - NETWORK_DATA.nodes.push(item); - - console.log(typeof item.id); - var link = { - source: item.id, - target: pdServiceData.c_id - }; - NETWORK_DATA.links.push(link); + } } }); - var index = {}; - - jiraIssueData.forEach(function(item) { - NETWORK_DATA.nodes.push(item); - index[item.key] = item; - }); - - jiraIssueData.forEach(function(item) { - if (item.isReq === true) { - var versionLink = { - source: item.id, - target: item.pdServiceVersion - }; - - NETWORK_DATA.links.push(versionLink); - } - - var parentItem = index[item.parentReqKey]; - - if (parentItem) { - var link = { - source: item.id, - target: parentItem.id - }; - NETWORK_DATA.links.push(link); - } - }); - - if (NETWORK_DATA.nodes.length === 0) { // 데이터가 없는 경우를 체크 - d3.select("#NETWORK_GRAPH").remove(); - d3.select(".network-graph").append("p").text('데이터가 없습니다.'); - return; - } - - d3.select(".network-graph").append("svg").attr("id","NETWORK_GRAPH"); - - /!******** network graph config ********!/ - var networkGraph = { - createGraph : function(){ - var links = NETWORK_DATA.links.map(function(d){ - return Object.create(d); - }); - var nodes = NETWORK_DATA.nodes.map(function(d){ - return Object.create(d); - }); - var fillCircle = function(g){ - if (g.type === "pdService") { - return "#c67cff"; - } else if (g.type === "version") { - return "rgb(255,127,14)"; - } else if (g.isReq === true) { - return "rgb(214,39,40)"; - } else if (g.isReq === false) { - return "rgb(31,119,180)"; - } else { - return "rgb(44,160,44)"; - } - }; - - var typeBinding = function(g) { - var name = ''; - - if (g.type === "pdService") { - name = '제품(서비스)'; - } else if (g.type === "version") { - name = '버전'; - } else if (g.isReq === true) { - name = '요구사항'; - } else if (g.isReq === false) { - name = '연결된 이슈'; - } - - return "[" + name + "]"; - }; - - var nameBinding = function(g) { - var name = ''; - - if (g.type === "pdService") { - return g.c_title; - } else if (g.type === "version") { - return g.c_title; - } else { - return g.key; - } - }; - - var width = 500; - var height = 500; - - var simulation = d3.forceSimulation(nodes) - .force("link", d3.forceLink(links).id( function(d){ return d.id; })) - .force("charge", d3.forceManyBody().strength(-100)) - .force("center", d3.forceCenter(width / 3, height / 3)); - // .force("collide",d3.forceCollide().radius( function(d){ return d.value*8}) ); - - //simulation.stop(); // stop 필요한가? - - var svg = d3.select("#NETWORK_GRAPH") - .attr("viewBox", [0, 0, width, height]); - - var initScale; - - if (NETWORK_DATA.nodes.length > 200) { - initScale = 0.2; - } else if (NETWORK_DATA.nodes.length > 90) { - initScale = 0.4; - } else { - initScale = 1; - } - - var initialTransform = d3.zoomIdentity - .translate(width / 3, height / 3) // 초기 위치 설정 - .scale(initScale); // 초기 줌 레벨 설정 - - var zoom = d3.zoom() - .scaleExtent([0.1, 5]) // 줌 가능한 최소/최대 줌 레벨 설정 - .on("zoom", zoomed); // 줌 이벤트 핸들러 설정 - - // SVG에 확대/축소 기능 적용 - svg.call(zoom); - - // 초기 줌 설정 - svg.transition().duration(500).call(zoom.transform, initialTransform); - - var gHolder = svg.append("g") - .attr("class", "g-holder"); - - var link = gHolder.append("g") - .attr("fill", "none") - .attr("stroke", "gray") - .attr("stroke-opacity", 1) - .selectAll("path") - .data(links) - .join("path") - .attr("stroke-width", 1.5); - - /!* - var node = svg.append("g") - .selectAll("circle") - .data(nodes) - .enter() - .append("circle") - .attr("r", 8) - .attr("fill", color) - .call(drag(simulation)); // text 라벨 추가를 위해 g로 그룹핑 - - node.append("text") - .text(function(d){ return d.id }) - .style("font-size", "12px") *!/ - - var node = gHolder.append("g") - .attr("class", "circle-node-holder") - .attr("stroke", "white") - .attr("stroke-width", 1) - .selectAll("g") - .data(nodes) - .enter() - .append("g") - .each(function(d){ - d3.select(this) - .append("circle") - .attr("r", 10) - .attr("fill", fillCircle(d)); - /!*d3.select(this) - .append("text").text(d.id) - .attr("dy",6) - .style("text-anchor","middle") - .attr("class", "node-label");*!/ - }).call(networkGraph.drag(simulation)); - - node.append("text") - .attr("x", 11) - .attr("dy", ".31em") - .style("font-size", "9px") - .style("fill", (d) => fillCircle(d)) - .style("font-weight", "5") - .attr("stroke", "white") - .attr("stroke-width", "0.3") - .text((d) => typeBinding(d)); - - node.append("text") - .attr("x", 12) - .attr("dy", "1.5em") - .style("font-family", "Arial") - .style("font-size", "10px") - .style("font-weight", "10") - .text((d) => nameBinding(d)); - - simulation.on("tick", function(){ - link.attr("x1", function(d){ return d.source.x; }) - .attr("y1", function(d){ return d.source.y; }) - .attr("x2", function(d){ return d.target.x; }) - .attr("y2", function(d){ return d.target.y; }); - - /!*node - .attr("cx", function(d){ return d.x; }) - .attr("cy", function(d){ return d.y; });*!/ - - //circle 노드에서 g 노드로 변경 - node.attr("transform", function(d) { return "translate("+d.x+","+ d.y+")"; }); - - link.attr("d", function(d) { - var dx = d.target.x - d.source.x, - dy = d.target.y - d.source.y, - dr = Math.sqrt(dx * dx + dy * dy); - return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; - }); - }); - - function zoomed() { - // 현재 확대/축소 변환을 얻음 - var transform = d3.event.transform; - - // 모든 노드 및 링크를 현재 확대/축소 변환으로 이동/확대/축소 - gHolder.attr("transform", transform); - } - - //invalidation.then(() => simulation.stop()); - - return svg.node(); - }, - drag : function(simulation){ - function dragstarted(d) { - if (!d3.event.active) simulation.alphaTarget(0.3).restart(); - d.fx = d.x; - d.fy = d.y; - } - - function dragged(d) { - d.fx = d3.event.x; - d.fy = d3.event.y; - } - - function dragended(d) { - if (!d3.event.active) simulation.alphaTarget(0); - d.fx = null; - d.fy = null; - } - - return d3.drag() - .on("start", dragstarted) - .on("drag", dragged) - .on("end", dragended); - } - } - - /!******** network graph create ********!/ - networkGraph.createGraph(); -}*/ - -function formatDate(date) { - var year = date.getFullYear(); - var month = (1 + date.getMonth()).toString().padStart(2, '0'); - var day = date.getDate().toString().padStart(2, '0'); - - return year + '-' + month + '-' + day; } function calendarHeatMap(pdServiceLink, pdServiceVersions) { @@ -1748,8 +1148,7 @@ async: true, statusCode: { 200: function (data) { - // scatterChart(data); - + console.log(data); $(".update-title").show(); $('#calendar_yearview_blocks_chart_1').calendar_yearview_blocks({ @@ -1761,9 +1160,6 @@ colors: data.requirementColors }); - /*var heatMapBarHtml = `
`; - $('#calendar_yearview_blocks_chart_1').append(heatMapBarHtml);*/ - $('#calendar_yearview_blocks_chart_2').calendar_yearview_blocks({ data: JSON.stringify(data.relationIssue), start_monday: true, @@ -1780,99 +1176,8 @@ } -/*function calendarHeatMap(jiraIssueData, pdServiceLink, pdServiceVersions) { - - var jiraIssueBackupData; - - $('#calendar_yearview_blocks_chart_1 svg').remove(); - $('#calendar_yearview_blocks_chart_2 svg').remove(); - - var requirement = {}; - var relation_issue = {}; - var requirement_colors = []; - var relation_issue_colors = []; - - jiraIssueData.forEach(item => { - console.log(item.summary); - if(item.isReq === true) { - heatmapDataParsing(requirement, item, requirement_colors); - } - else { - heatmapDataParsing(relation_issue, item, relation_issue_colors); - } - }); - - function heatmapDataParsing(return_object, item, return_colors) { - var display_date = formatDate(new Date(item.updated)); - console.log(display_date + " : " +item.updated); - console.log(item.summary); - if (return_object[display_date] === undefined) { - return_object[display_date] = {}; - return_object[display_date].items = []; - } - - if (!return_object[display_date].items.includes(item.summary)) { - return_object[display_date].items.push(item.summary); - return_colors.push(item.summary); - } - } - - var requirementHeatMapData = JSON.stringify(requirement); - var relationIssuetHeatMapData = JSON.stringify(relation_issue); - - console.log(requirementHeatMapData); - var req_colors = { - 'default': '#eeeeee' - }; - - var issue_colors = { - 'default': '#eeeeee' - }; - - assignColors(requirement_colors, req_colors); - assignColors(relation_issue_colors, issue_colors); - - function assignColors(colorsArray, colorsObj) { - colorsArray.forEach((item) => { - if (item !== 'default') { - colorsObj[item] = getRandomColor(); - } - }); - } - - function getRandomColor() { - return '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0'); - } - - $(".update-title").show(); - - $('#calendar_yearview_blocks_chart_1').calendar_yearview_blocks({ - data: requirementHeatMapData, - start_monday: true, - always_show_tooltip: true, - month_names: ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sept', 'oct', 'nov', 'dec'], - day_names: ['mo', 'wed', 'fri', 'sun'], - colors: req_colors - }); - - /!*var heatMapBarHtml = `
`; - $('#calendar_yearview_blocks_chart_1').append(heatMapBarHtml);*!/ - - $('#calendar_yearview_blocks_chart_2').calendar_yearview_blocks({ - data: relationIssuetHeatMapData, - start_monday: true, - always_show_tooltip: true, - month_names: ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'], - day_names: ['mo', 'wed', 'fri', 'sun'], - colors: issue_colors - }); - - d3.select("#heatmap-body").style("overflow-x","scroll"); -}*/ - - //////////////////// -// 여섯번째 박스 +// 다섯번째 박스 //////////////////// function statusTimeline(data) { @@ -2014,9 +1319,8 @@ } //////////////////// -// 일곱번째 박스 +// 여섯번째 박스 //////////////////// - function sevenTimeline(data) { var sevenTimeLineDiv = document.getElementById("sevenTimeLine"); sevenTimeLineDiv.innerHTML = ""; @@ -2114,158 +1418,177 @@ } } -function scatterChart(data) { - console.log(data); - var requirementDataCount = {}; - var relationIssueDataCount = {}; +function candleStickChart() { + console.log("candle stick"); + var dom = document.getElementById('candlestick-chart-container'); + var myChart = echarts.init(dom, 'dark', { + renderer: 'canvas', + useDirtyRect: false + }); + var app = {}; - data.forEach(jiraissue => { - if(jiraissue.updated === null || jiraissue.updated === undefined) { - return; - } + var option; - var updatedDate = jiraissue.updated.split('T')[0]; - - if (jiraissue.isReq === true) { - if (!requirementDataCount[updatedDate]) { - requirementDataCount[updatedDate] = 0; + option = { + xAxis: { + data: ['2017-10-24', '2017-10-25', '2017-10-26', '2017-10-27'] + }, + yAxis: {}, + series: [ + { + type: 'candlestick', + data: [ + [20, 34, 10, 38], + [40, 35, 30, 50], + [31, 38, 33, 44], + [38, 15, 5, 42] + ] } - requirementDataCount[updatedDate]++; - } else { - if (!relationIssueDataCount[updatedDate]) { - relationIssueDataCount[updatedDate] = 0; + ], + tooltip: { + trigger: 'axis', + position: 'top', + borderWidth: 1, + axisPointer: { + type: 'cross' } - relationIssueDataCount[updatedDate]++; - } - }); + }, + backgroundColor: 'rgba(255,255,255,0)', + }; - var requirementData = Object.keys(requirementDataCount).map(key => { - var dateObj = new Date(key+'T00:00:00'); - return [dateObj, requirementDataCount[key]]; - }); + if (option && typeof option === 'object') { + myChart.setOption(option); + } - var relationIssueData = Object.keys(relationIssueDataCount).map(key => { - var dateObj = new Date(key+'T00:00:00'); - return [dateObj, relationIssueDataCount[key]]; - }); + window.addEventListener('resize', myChart.resize); +} +//////////////////// +// 레이더 차트 +//////////////////// +/* +function radarChart(pdServiceId, pdServiceVersionList) { - var dom = document.getElementById('scatter-chart-container'); + var maxCount; + var versionText = []; + var reqCount = []; - var myChart = echarts.init(dom, 'dark', { - renderer: 'canvas', - useDirtyRect: false - }); - var app = {}; + var _url = "/auth-user/api/arms/dashboard/normal/"+pdServiceId; + $.ajax({ + url: _url, + type: "GET", + data: { "서비스아이디" : pdServiceId, + "메인그룹필드" : "pdServiceVersion", + "isReq" : true, + "컨텐츠보기여부" : false, + "크기" : 1000 + }, + contentType: "application/json;charset=UTF-8", + dataType: "json", + progress: true, + async: false, + statusCode: { + 200: function (data) { + maxCount = data.전체합계; + var result = data.검색결과.group_by_pdServiceVersion; - var option; + result.forEach(item => { + if (versionListData[item.필드명]) { + versionListData[item.필드명].totalCount = item.개수; + } + }); - if ((requirementData && requirementData.length > 0) || (relationIssueData && relationIssueData.length > 0) ) { + Object.values(versionListData).forEach(item => { + var version = {}; + version.text = item.c_title; + version.max = maxCount; - option = { - aria: { - show: true - }, - legend: { - data: ['요구사항' , '연결된 이슈'] // 여기에 실제 데이터 종류를 적어주세요 - }, - /* toolbox: { - left: 'left', - feature: { - dataView: {}, - saveAsImage: {}, - dataZoom: {} + versionText.push(version); + reqCount.push(item.totalCount); + }); + } + } + }); + + var chart = echarts.init(document.getElementById('radar-chart-main')); + + chart.setOption({ + color: ['#E49400'], + dataZoom: [ + { // The first dataZoom component + radiusAxisIndex: [0, 2] // Indicates that this dataZoom component + // controls the first and the third radiusAxis + } + ], + aria: { + show: false + }, + tooltip: {}, + legend: { + data: [{ + icon: 'circle', + name: '요구사항' + }], + textStyle: { + color: 'white', // 원하는 텍스트 색상으로 변경합니다. + fontSize: 14 + } + }, + radar: { + radius: [0, '50%'], + triggerEvent: true, + // shape: 'circle', + indicator: versionText, + name: { + rotate: 45, // 텍스트를 45도로 회전시킵니다. + position: 'outside', // 텍스트를 레이더 영역 내부에 위치시킵니다. + color: '#ffffff', + formatter: function(text) { + // 줄바꿈을 위해 '\n' 문자를 삽입합니다. + var wrappedValue = text.replace(/(.{12})/g, '$1\n'); // 10자마다 줄바꿈 + return '[' + wrappedValue + ']'; + }, + rich: { + value: { + align: 'left', + color: '#ffffff', + lineHeight: 10 // 줄 간격을 설정합니다. + } } - },*/ - xAxis: { - type: 'time', - splitLine: { - show: true + } + }, + series: [{ + name: '', + type: 'radar', + label: { + normal: { + show: true, + textStyle: { + color: 'white' // 원하는 텍스트 색상으로 변경합니다. + } } }, - yAxis: { - type: 'value', - splitLine: { - show: true - } + itemStyle: { + borderWidth: 2, + borderColor: '#fff' }, - series: [ + // areaStyle: {normal: {}}, + data : [ { - name: '요구사항', - data: requirementData, - type: 'scatter', - symbol: 'diamond', - label: { - emphasis: { - show: true, - color: '#FFFFFF' - } - }, - symbolSize: function (val) { - var sbSize = 10; - if (val[1] > 10) { - sbSize = val[1] * 1.1; - } - return sbSize; - }, - }, - { - name: '연결된 이슈', - data: relationIssueData, - type: 'scatter', - label: { - emphasis: { - show: true - } - }, - symbolSize: function (val) { - var sbSize = 10; - if (val[1] > 10) { - sbSize = val[1] * 1.1; - } - return sbSize; - }, - itemStyle: { - color: '#13de57' - }, + value: reqCount, + name: '요구사항' } ], - tooltip: { - trigger: 'axis', - position: 'top', - borderWidth: 1, - axisPointer: { - type: 'cross' - } - }, - backgroundColor: 'rgba(255,255,255,0)', - animationDelay: function (idx) { - return idx * 20; - }, - animationDelayUpdate: function (idx) { - return idx * 20; + symbol: 'circle', + symbolSize: 7, + symbolRotate: function(value, params) { + return ~~(360 * Math.random()); } - }; - - myChart.on('click', function (params) { - console.log(params.data); - }); - - } - else { - option = { - title: { - text: '데이터가 없습니다', - left: 'center', - top: 'middle' - }, - backgroundColor: 'rgba(255,255,255,0)', - }; - } - - if (option && typeof option === 'object') { - myChart.setOption(option, true); - } - - window.addEventListener('resize', myChart.resize); -} \ No newline at end of file + } + ] + }); + window.addEventListener('resize', function () { + chart.resize(); + }); +} +*/ \ No newline at end of file