FishEye: Tag fed30a6b92ea8a3909b74fbe1daadf0d9dda0863 refers to a dead (removed) revision in file `arms/js/analysis/Cost/circularPackingChart.js'. FishEye: No comparison available. Pass `N' to diff? Index: arms/js/analysis/cost/circularPackingChart.js =================================================================== diff -u --- arms/js/analysis/cost/circularPackingChart.js (revision 0) +++ arms/js/analysis/cost/circularPackingChart.js (revision fed30a6b92ea8a3909b74fbe1daadf0d9dda0863) @@ -0,0 +1,348 @@ +function drawCircularPacking(target, psServiceName,rawData, colorArr) { + var chartDom = document.getElementById(target); + var myChart = echarts.init(chartDom); + var option; + // ChartWithFooter 관련 + let reqCount = 0; // total + let statusCounts = {}; + let statusDataArr = []; + + var colorPalette = [ //e chart 컬러 팔레트 + '#546570', '#c4ccd3' , '#749f83','#91c7ae' + ]; + + if(rawData) { + run(rawData); + } + + function run(rawData) { + const dataWrap = prepareData(rawData); + + console.log(dataWrap); + + initChart(dataWrap.seriesData, dataWrap.maxDepth); + } + + function prepareData(rawData) { + const seriesData = []; + let maxDepth = 0; + let index = 0; + + function convert(source, basePath, depth) { + maxDepth = Math.max(maxDepth, depth); + let value = 0; + let version, req_name; // version과 req_name을 선언 + + for (let key in source) { + let path = `${basePath}.${key}`; + if (Array.isArray(source[key])) { + let subValue = 0; + source[key].forEach(item => { + for(let subkey in item) { + let subPath = `${path}.${subkey}`; + let subsubValue = 0; + item[subkey].forEach(subItem => { + version = subItem.version; // version 업데이트 + req_name = subItem.req_name; // req_name 업데이트 + let itemPath = `${subPath}.${subItem.project}`; + subsubValue += subItem.cost; + seriesData.push({ + id: itemPath, + value: subItem.cost, + depth: depth + 3, + index: index++, + version: version, + req_name: req_name + }); // 3 depth + }); + if (subsubValue !== 0) { + subValue += subsubValue; + seriesData.push({ + id: subPath, + value: subsubValue, + depth: depth + 2, + index: index++, + version: version, + req_name: req_name + }); // 2 depth + } + } + }); + if (subValue !== 0) { + value += subValue; + seriesData.push({ + id: path, + value: subValue, + depth: depth + 1, + index: index++, + version: version, + req_name: req_name + }); + } + } else if (typeof source[key] === 'object' && source[key] !== null) { + value += convert(source[key], path, depth + 1); + } + } + + if (depth > 0) { + seriesData.push({ + id: basePath, + value: value, + depth: depth, + index: index++, + version: version, + req_name: req_name + }); + } + + return value; + } + + let totalValue = convert(rawData, psServiceName, 0); + + // 최상단 노드의 value를 업데이트 + seriesData.push({ + id: psServiceName, + value: totalValue, + depth: 0, + index: index + }); + + return { + seriesData: seriesData, + maxDepth: maxDepth + }; + } + + + function initChart(seriesData, maxDepth) { + console.log("seriesData ===> ") + console.log(seriesData); + var displayRoot = stratify(); + function stratify() { + return d3 + .stratify() + .parentId(function (d) { + return d.id.substring(0, d.id.lastIndexOf('.')); + })(seriesData) + .sum(function (d) { + return d.value || 0; + }) + .sort(function (a, b) { + return b.value - a.value; + }); + } + function overallLayout(params, api) { + var context = params.context; + d3 + .pack() + .size([api.getWidth() - 2, api.getHeight() - 2]) + .padding(3)(displayRoot); + context.nodes = {}; + displayRoot.descendants().forEach(function (node, index) { + context.nodes[node.id] = node; + }); + } + function renderItem(params, api) { + var context = params.context; + // Only do that layout once in each time `setOption` called. + if (!context.layout) { + context.layout = true; + overallLayout(params, api); + } + var nodePath = api.value('id'); + var node = context.nodes[nodePath]; + if (!node) { + // Reder nothing. + return; + } + var isLeaf = !node.children || !node.children.length; + var focus = new Uint32Array( + node.descendants().map(function (node) { + return node.data.index; + }) + ); + var nodeName = isLeaf + ? nodePath + .slice(nodePath.lastIndexOf('.') + 1) + .split(/(?=[A-Z][^A-Z])/g) + .join('\n') + : ''; + var z2 = api.value('depth') * 2; + return { + type: 'circle', + focus: focus, + shape: { + cx: node.x, + cy: node.y, + r: node.r + }, + transition: ['shape'], + z2: z2, + textContent: { + type: 'text', + style: { + // transition: isLeaf ? 'fontSize' : null, + text: nodeName, + fontFamily: 'Arial', + width: node.r * 1.3, + overflow: 'truncate', + fontSize: node.r / 3 + }, + emphasis: { + style: { + overflow: null, + fontSize: Math.max(node.r / 3, 12) + } + } + }, + textConfig: { + position: 'inside' + }, + style: { + fill: api.visual('color') + }, + emphasis: { + style: { + fontFamily: 'Arial', + fontSize: 12, + shadowBlur: 20, + shadowOffsetX: 3, + shadowOffsetY: 5, + shadowColor: 'rgba(0,0,0,0.3)' + } + } + }; + } + + let productCost = seriesData.find(function(data) { + return data.depth === 0; + }).value; + option = { + dataset: { + source: seriesData + }, + tooltip: { + confine: true + }, + visualMap: [ + { + show: false, + min: 0, + max: maxDepth, + dimension: 'depth', + inRange: {} // 색 일괄 지정을 하지 않아도. 빈값으로 두어야 합니다. + } + ], + hoverLayerThreshold: Infinity, + series: { + type: 'custom', + renderItem: renderItem, + progressive: 0, + coordinateSystem: 'none', + itemStyle: { + color: function(params) { + if (params.data.value) { + return colorPalette[params.value.depth]; + } else { + return "rgba(55,125,184,0.62)"; + } + } + }, + tooltip: { + formatter: function(params) { + // params.value에는 원본 값이 들어있을 것입니다. 여기에 단위를 붙여 반환하면 됩니다. + let id = params.data.id; + let parts = id.split('.'); + + if(params.data.value) { + if(params.data.depth === 0){ + return "제품(서비스) 정보
● 제품(서비스) :"+ parts[0] +"
● 비용 :"+params.data.value ; + }else if(params.data.depth === 1){ + return "버전 정보
● 버전 :"+ params.data.version +"
● 비용 :"+params.data.value ; + }else if(params.data.depth === 2){ + return "요구사항 정보
● 버전 :"+ params.data.version +"
● 요구사항 :"+ params.data.req_name +"
● 비용 :"+params.data.value ; + }else if(params.data.depth === 3){ + return "요구사항 키 정보
● 버전 :"+ params.data.version +"
● 요구사항 :"+ params.data.req_name +"
● 요구사항 키 :"+ parts[3] +"
● 비용 :"+params.data.value ; + } + } else { + return `${params.data.id}`; + } + } + } + }, + graphic: [ + { + type: 'group', + left: 20, + top: 20, + children: [ + { + type: 'text', + z: 100, + left: 0, + top: 0, + style: { + text: [ + '{a| 제품 비용 }', + '{a| ' + productCost + '}' + ].join('\n'), + rich: { + a: { + fontSize: 13, + fontWeight: 'bold', + lineHeight: 20, + fontFamily: 'Arial', + fill: 'white' + } + } + } + } + ] + } + ] + }; + + option && myChart.setOption(option, true); + myChart.on('click', { seriesIndex: 0 }, function (params) { + drillDown(params.data.id); + }); + + function drillDown(targetNodeId) { + displayRoot = stratify(); + if (targetNodeId != null) { + displayRoot = displayRoot.descendants().find(function (node) { + return node.data.id === targetNodeId; + }); + } + // A trick to prevent d3-hierarchy from visiting parents in this algorithm. + displayRoot.parent = null; + myChart.setOption({ + dataset: { + source: seriesData + } + }); + } + // Reset: click on the blank area. + myChart.getZr().on('click', function (event) { + if (!event.target) { + drillDown(); + } + }); + } + + + + + function replaceNaN(value) { + if (isNaN(value)) { + return " - "; + } else { + return value; + } + } + + window.addEventListener('resize', function () { + myChart.resize(); + }); +} Index: arms/js/analysisCost.js =================================================================== diff -u -r83edfd67668048e964394a067f6326e29b3d937b -rfed30a6b92ea8a3909b74fbe1daadf0d9dda0863 --- arms/js/analysisCost.js (.../analysisCost.js) (revision 83edfd67668048e964394a067f6326e29b3d937b) +++ arms/js/analysisCost.js (.../analysisCost.js) (revision fed30a6b92ea8a3909b74fbe1daadf0d9dda0863) @@ -61,7 +61,7 @@ "js/analysis/topmenu/topMenu.js", //CirclePacking with d3 Chart - "js/analysis/Cost/circularPackingChart.js" + "js/analysis/cost/circularPackingChart.js" ], [ "../reference/jquery-plugins/dataTables-1.10.16/media/css/jquery.dataTables_lightblue4.css", @@ -841,81 +841,54 @@ ///////////////////////////////////////////////////////// function getReqCostRatio(pdServiceLink, pdServiceVersionLinks) { - let paramData = { - "요구_사항" : { - 'isReqType': 'REQUIREMENT', - 'pdServiceLink' : selectedPdServiceId, - 'pdServiceVersionLinks' : pdServiceVersionLinks,//[16,17,18] - '메인그룹필드' : 'pdServiceVersion', - '컨텐츠보기여부' : false, - '크기' : 10000, - '하위그룹필드들' : ['key','assignee.assignee_emailAddress.keyword'], - '하위크기' : 10000 - }, - "하위_이슈_사항" : { - 'isReqType': 'ISSUE', - 'pdServiceLink': selectedPdServiceId, - 'pdServiceVersionLinks': pdServiceVersionLinks, - '메인그룹필드': 'parentReqKey', - '컨텐츠보기여부': false, - '크기': 10000, - '하위그룹필드들': ['assignee.assignee_emailAddress.keyword'],//'[assignee.assignee_emailAddress.keyword]', - '하위크기': 10000 - } - } + const url = new UrlBuilder() + .setBaseUrl("/auth-user/api/arms/analysis/cost/req-activated-issue") + .addQueryParam("pdServiceLink", pdServiceLink) + .addQueryParam("pdServiceVersionLinks", pdServiceVersionLinks) + .build(); + $.ajax({ - url: "/auth-user/api/arms/analysis/scope/req-status-and-reqInvolved-unique-assignees", - type: "POST", + url: url, + type: "GET", contentType: "application/json;charset=UTF-8", dataType: "json", - data: JSON.stringify(paramData), progress: true, statusCode: { 200: function (result) { -// console.log("[ analysisScope :: getReqCostRatio ] :: result"); -// console.log(result); + console.log("[ analysisCost :: getReqCostRatio ] :: = "); + console.log(result); + let 변환된_데이터 = {}; + + Object.keys(result.버전별_그룹).forEach((버전) => { + let 요구사항별_그룹 = result.버전별_그룹[버전].요구사항별_그룹; + let 변환된_요구사항들 = []; + Object.keys(요구사항별_그룹).forEach((요구사항) => { + let 변환된_요구사항 = {}; + 변환된_요구사항[요구사항] = 요구사항별_그룹[요구사항].map((데이터) => { + let 치환된_버전 = 데이터.c_pds_version_name; + let 치환된_요구사항 = 데이터.c_req_name; + return { + project: 데이터.c_issue_key, + cost: 300, // 임시데이터 + version: 데이터.c_pds_version_name, + req_name : 데이터.c_req_name + }; + }); + 변환된_요구사항들.push(변환된_요구사항); + }); + + 변환된_데이터[버전] = 변환된_요구사항들; + }); + + console.log(변환된_데이터); + let pdServiceName; pdServiceListData.forEach(elements => { if (elements["pdServiceId"] === +pdServiceLink) { - pdServiceName = elements["pdServiceName"]; + pdServiceName = elements["pdServiceName"]; } }); - - let data = { - "1_0_1": [ - { - "요구사항": [ - { "project": "TE-1", "cost": 400 }, - { "project": "TE-2", "cost": 400 }, - { "project": "TE-3", "cost": 400 } - ] - }, - { - "요구사항2": [ - { "project": "TT-1", "cost": 300 }, - { "project": "TT-2", "cost": 300 }, - { "project": "TT-3", "cost": 300 } - ] - } - ], - "1_0_2": [ - { - "요구사항3": [ - { "project": "TE-4", "cost": 100 }, - { "project": "TE-5", "cost": 100 }, - { "project": "TE-6", "cost": 100 } - ] - }, - { - "요구사항4": [ - { "project": "TT-4", "cost": 300 }, - { "project": "TT-5", "cost": 300 }, - { "project": "TT-6", "cost": 300 } - ] - } - ] - }; - drawCircularPacking("circularPacking",pdServiceName,data); + drawCircularPacking("circularPacking",pdServiceName,변환된_데이터); } } });