Index: arms/html/analysisScope/content-container.html =================================================================== diff -u -rf53218e3b68e19c2d17937b91a3f130ca5f8345b -r6993b6519461e4671fc8f57194e14912edf6bdda --- arms/html/analysisScope/content-container.html (.../content-container.html) (revision f53218e3b68e19c2d17937b91a3f130ca5f8345b) +++ arms/html/analysisScope/content-container.html (.../content-container.html) (revision 6993b6519461e4671fc8f57194e14912edf6bdda) @@ -674,7 +674,7 @@
-
+

-
+

Index: arms/js/analysis/mockData/circularPackingEx.json =================================================================== diff -u --- arms/js/analysis/mockData/circularPackingEx.json (revision 0) +++ arms/js/analysis/mockData/circularPackingEx.json (revision 6993b6519461e4671fc8f57194e14912edf6bdda) @@ -0,0 +1,239 @@ +{ + "Baseversion": { + "$count": 1250, + "yAxisIndex": { + "$count": 100 + }, + "startValue": { + "$count": 300 + }, + "endValue": { + "$count": 500 + }, + "xAxisIndex": { + "$count": 700 + }, + "angleAxisIndex": { + "$count": 900 + }, + "filterMode": { + "$count": 1100 + }, + "type": { + "$count": 900 + }, + "start": { + "$count": 700 + }, + "orient": { + "$count": 500 + }, + "radiusAxisIndex": { + "$count": 300 + }, + "throttle": { + "$count": 100 + }, + "end": { + "$count": 100 + }, + "zoomLock": { + "$count": 200 + } + }, + "버전1_0_1": { + "$count": 3744, + "요구사항1": { + "$count": 757, + "title": { + "$count": 55, + "zoom": { + "$count": 23 + }, + "back": { + "$count": 14 + } + }, + "show": { + "$count": 650 + }, + "iconStyle": { + "normal": { + "$count": 20, + "shadowBlur": { + "$count": 1 + }, + "color": { + "$count": 1 + }, + "borderColor": { + "$count": 1 + } + }, + "$count": 38, + "emphasis": { + "$count": 11, + "color": { + "$count": 1 + } + } + }, + "yAxisIndex": { + "$count": 43 + }, + "xAxisIndex": { + "$count": 75 + }, + "icon": { + "$count": 33, + "zoom": { + "$count": 26 + }, + "back": { + "$count": 15 + } + } + }, + "요구사항2": { + "type": { + "$count": 121 + }, + "$count": 692, + "backgroundColor": { + "$count": 99 + }, + "excludeComponents": { + "$count": 125 + }, + "show": { + "$count": 97 + }, + "title": { + "$count": 98 + }, + "icon": { + "$count": 128 + }, + "iconStyle": { + "normal": { + "$count": 52, + "color": { + "$count": 19 + }, + "opacity": { + "$count": 7 + }, + "shadowOffsetY": { + "$count": 3 + }, + "shadowOffsetX": { + "$count": 7 + }, + "shadowBlur": { + "$count": 12 + }, + "shadowColor": { + "$count": 11 + }, + "borderColor": { + "$count": 14 + }, + "borderWidth": { + "$count": 5 + } + }, + "emphasis": { + "$count": 61, + "color": { + "$count": 10 + }, + "shadowBlur": { + "$count": 3 + }, + "opacity": { + "$count": 4 + }, + "borderColor": { + "$count": 4 + }, + "shadowOffsetX": { + "$count": 2 + }, + "shadowColor": { + "$count": 3 + }, + "shadowOffsetY": { + "$count": 1 + }, + "borderWidth": { + "$count": 1 + } + }, + "$count": 87 + }, + "pixelRatio": { + "$count": 9 + }, + "name": { + "$count": 14 + } + }, + "요구사항3": { + "$count": 681 + }, + "restore": { + "$count": 383, + "iconStyle": { + "normal": { + "borderColor": { + "$count": 7 + }, + "$count": 33, + "color": { + "$count": 12 + }, + "shadowColor": { + "$count": 4 + }, + "opacity": { + "$count": 7 + }, + "shadowOffsetX": { + "$count": 3 + }, + "shadowBlur": { + "$count": 6 + }, + "borderWidth": { + "$count": 4 + }, + "shadowOffsetY": { + "$count": 3 + } + }, + "$count": 24, + "emphasis": { + "shadowBlur": { + "$count": 1 + }, + "$count": 20, + "color": { + "$count": 1 + }, + "borderColor": { + "$count": 1 + } + } + }, + "show": { + "$count": 35 + }, + "title": { + "$count": 24 + }, + "icon": { + "$count": 35 + } + } + } +} \ No newline at end of file Index: arms/js/analysis/resource/chart/circularPackingChart.js =================================================================== diff -u --- arms/js/analysis/resource/chart/circularPackingChart.js (revision 0) +++ arms/js/analysis/resource/chart/circularPackingChart.js (revision 6993b6519461e4671fc8f57194e14912edf6bdda) @@ -0,0 +1,413 @@ +function exampleCircularPackingChart() { + var chartDom = document.getElementById('circularPacking'); + var myChart = echarts.init(chartDom); + var option; + + $.when( + $.get("./js/analysis/mockData/circularPackingEx.json"), + $.getScript( + "./js/analysisTime/d3.v5.min.js" + // "../reference/jquery-plugins/d3-7.8.2/dist/d3.min.js" + /*'https://fastly.jsdelivr.net/npm/d3-hierarchy@2.0.0/dist/d3-hierarchy.min.js'*/ + ) + ).done(function (res) { + run(res[0]); + }); + function run(rawData) { + const dataWrap = prepareData(rawData); + console.log(dataWrap); + initChart(dataWrap.seriesData, dataWrap.maxDepth); + } + function prepareData(rawData) { + const seriesData = []; + let maxDepth = 0; + function convert(source, basePath, depth) { + if (source == null) { + return; + } + if (maxDepth > 5) { + return; + } + maxDepth = Math.max(depth, maxDepth); + seriesData.push({ + id: basePath, + value: source.$count, + depth: depth, + index: seriesData.length + }); + for (var key in source) { + if (source.hasOwnProperty(key) && !key.match(/^\$/)) { + var path = basePath + '.' + key; + convert(source[key], path, depth + 1); + } + } + } + convert(rawData, '제품-이름', 0); + return { + seriesData: seriesData, + maxDepth: maxDepth + }; + } + function initChart(seriesData, maxDepth) { + 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)' + } + } + }; + } + option = { + dataset: { + source: seriesData + }, + tooltip: {}, + visualMap: [ + { + show: false, + min: 0, + max: maxDepth, + dimension: 'depth', + inRange: { + color: ["#264961", "#4A8FBD", "#82A5BD", "#5E7788", "#5D8AA8", "#2c5571"]//['#006edd', '#e0ffff'] + } + } + ], + hoverLayerThreshold: Infinity, + series: { + type: 'custom', + renderItem: renderItem, + progressive: 0, + coordinateSystem: 'none', + encode: { + tooltip: 'value', + itemName: 'id' + } + } + }; + myChart.setOption(option); + 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(); + } + }); + } + + option && myChart.setOption(option, true); + window.addEventListener('resize', function () { + myChart.resize(); + }); +} + +function drawCircularPacking(target, psServiceName) { + var chartDom = document.getElementById('circularPacking'); + var myChart = echarts.init(chartDom); + var option; + + $.when( + $.get("./js/analysis/mockData/circularPackingEx.json"), + $.getScript( + "./js/analysisTime/d3.v5.min.js" + ) + ).done(function (res) { + run(res[0]); + }); + function run(rawData) { + const dataWrap = prepareData(rawData); + initChart(dataWrap.seriesData, dataWrap.maxDepth); + } + function prepareData(rawData) { + const seriesData = []; + let maxDepth = 0; + function convert(source, basePath, depth) { + if (source == null) { + return; + } + if (maxDepth > 5) { + return; + } + maxDepth = Math.max(depth, maxDepth); + seriesData.push({ + id: basePath, + value: source.$count, + depth: depth, + index: seriesData.length + }); + for (var key in source) { + if (source.hasOwnProperty(key) && !key.match(/^\$/)) { + var path = basePath + '.' + key; + convert(source[key], path, depth + 1); + } + } + } + convert(rawData, psServiceName, 0); // 첫번째 Node 이름 설정. + return { + seriesData: seriesData, + maxDepth: maxDepth + }; + } + function initChart(seriesData, maxDepth) { + 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)' + } + } + }; + } + option = { + dataset: { + source: seriesData + }, + tooltip: {}, + visualMap: [ + { + show: false, + min: 0, + max: maxDepth, + dimension: 'depth', + inRange: { + color: ["#182E3D", "#4A8FBD", "#82A5BD", "#5E7788", "#5D8AA8", "#2c5571"]//['#006edd', '#e0ffff'] + } + } + ], + hoverLayerThreshold: Infinity, + series: { + type: 'custom', + renderItem: renderItem, + progressive: 0, + coordinateSystem: 'none', + encode: { + tooltip: 'value', + itemName: 'id' + } + } + }; + myChart.setOption(option); + 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(); + } + }); + } + + option && myChart.setOption(option, true); + window.addEventListener('resize', function () { + myChart.resize(); + }); +} + Index: arms/js/analysisScope.js =================================================================== diff -u -rf53218e3b68e19c2d17937b91a3f130ca5f8345b -r6993b6519461e4671fc8f57194e14912edf6bdda --- arms/js/analysisScope.js (.../analysisScope.js) (revision f53218e3b68e19c2d17937b91a3f130ca5f8345b) +++ arms/js/analysisScope.js (.../analysisScope.js) (revision 6993b6519461e4671fc8f57194e14912edf6bdda) @@ -62,6 +62,8 @@ //tree chart //CirclePacking with d3 Chart + "js/analysis/resource/chart/circularPackingChart.js", + "js/analysis/mockData/circularPackingEx.json" ], [ "../reference/jquery-plugins/dataTables-1.10.16/media/css/jquery.dataTables_lightblue4.css", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Responsive/css/responsive.dataTables_lightblue4.css", @@ -96,6 +98,7 @@ versionUpdateIssueScatterChart(); dashboardColor = dashboardPalette.dashboardPalette01; + exampleCircularPackingChart(); // circularPackingChart - MockData }) .catch(function() { console.error('플러그인 로드 중 오류 발생'); @@ -933,9 +936,7 @@ 200: function (result) { console.log("[ analysisScope :: getReqAndSubtaskPerVersion ] :: result"); console.log(result); - console.log(versionListData); - let legend_arr = ["요구사항", "연결이슈"]; let verDataArr = [];