diff --git a/metadata/static/catalog/js/panorama-generator.js b/metadata/static/catalog/js/panorama-generator.js index c1ad8b3..48da4af 100644 --- a/metadata/static/catalog/js/panorama-generator.js +++ b/metadata/static/catalog/js/panorama-generator.js @@ -110,7 +110,13 @@ d3.json(url, function(error, data) { // Time Overall chart: - var overallVolumeChart = dc.lineChart("#timelineChart"); + // https://dc-js.github.io/dc.js/docs/html/dc.lineChart.html + var statusChart = dc.compositeChart("#timelineChart"); + + // Please check at https://github.com/dc-js/dc.js/issues/878 + // for a bug preventing brush filter to work properly on multiline + // charts. + // Set the range of time x-axis: var timeParser = d3.time.format("%Y-%m-%d"); @@ -126,54 +132,131 @@ d3.json(url, function(error, data) { } } - // https://github.com/dc-js/dc.js/wiki/FAQ#what-if-the-rows-contain-multiple-values - - function reduceFieldsAdd(fields) { - return function(p, v) { - fields.forEach(function(f) { - p[f] += v[f]; - }); - return p; - }; + var overallDim = ndx.dimension(function(d) { return timeParser.parse(d["identification_date"]); }); + + // I was unable to pass the status value as a parameter + // so I had to reduce one by one: + + //Reduce "Solved" entries: + function reduceSolvedAdd(p,v) { + if (v['status'] == "Solved") + p.status += +1; + return p; + } + + function reduceSolvedRemove(p,v) { + if (v['status'] == "Solved") + p.status -= +1; + return p; } - function reduceFieldsRemove(fields) { - return function(p, v) { - fields.forEach(function(f) { - p[f] -= v[f]; - }); - return p; - }; + + //Reduce "Notified" entries: + function reduceNotifiedAdd(p,v) { + if (v['status'] == "Notified") + p.status += +1; + return p; } - function reduceFieldsInitial(fields) { - return function() { - var ret = {}; - fields.forEach(function(f) { - ret[f] = 0; - }); - return ret; - }; + + function reduceNotifiedRemove(p,v) { + if (v['status'] == "Notified") + p.status -= +1; + return p; } - var fields = ['status']; - var overallDim = ndx.dimension(function(d) { return timeParser.parse(d["identification_date"]); }); -// var overallGroup = overallDim.group().reduceCount(function(d) { return d.identification_date; }); - var overallGroup = overallDim.group().reduce(reduceFieldsAdd(fields), reduceFieldsRemove(fields), reduceFieldsInitial(fields)); + //Reduce "Mitigated" entries: + function reduceMitigatedAdd(p,v) { + if (v['status'] == "Mitigated") + p.status += +1; + return p; + } + + function reduceMitigatedRemove(p,v) { + if (v['status'] == "Mitigated") + p.status -= +1; + return p; + } + //Reduce "Not identified" entries: + function reduceNIdentifiedAdd(p,v) { + if (v['status'] == "Not identified") + p.status += +1; + return p; + } + + function reduceNIdentifiedRemove(p,v) { + if (v['status'] == "Not identified") + p.status -= +1; + return p; + } + + //Reduce "Risk accepted" entries: + function reduceRiskAcceptedAdd(p,v) { + if (v['status'] == "Risk accepted") + p.status += +1; + return p; + } + + function reduceRiskAcceptedRemove(p,v) { + if (v['status'] == "Risk accepted") + p.status -= +1; + return p; + } -console.log(overallDim.top(Infinity)); -console.log(overallGroup.top(Infinity)); - overallVolumeChart - .x(d3.time.scale().domain([min, max])) - .dimension(overallDim) - .group(overallGroup) - .legend(dc.legend().x(80).y(20).itemHeight(13).gap(5)) - .elasticX(true); + function reduceInitial() { + return { + identification_date:0, + status:0 + }; + } + + var notifiedGroup = overallDim.group().reduce(reduceNotifiedAdd, reduceNotifiedRemove, reduceInitial); + + var solvedGroup = overallDim.group().reduce(reduceSolvedAdd, reduceSolvedRemove, reduceInitial); + + var mitigatedGroup = overallDim.group().reduce(reduceMitigatedAdd, reduceMitigatedRemove, reduceInitial); + + var nIdentifiedGroup = overallDim.group().reduce(reduceNIdentifiedAdd, reduceNIdentifiedRemove, reduceInitial); + var riskAcceptedGroup = overallDim.group().reduce(reduceRiskAcceptedAdd, reduceRiskAcceptedRemove, reduceInitial); + + statusChart + .x(d3.time.scale().domain([min, max])) + .yAxisLabel("Vulnerabilities") + .elasticX(true) + .legend(dc.legend().x(80).y(20).itemHeight(13).gap(5)) + .compose([ + dc.lineChart(statusChart) + .dimension(overallDim) + .colors('grey') + .valueAccessor(function (d) { return d.value.status }) + .group(notifiedGroup, "Notified"), + dc.lineChart(statusChart) + .dimension(overallDim) + .colors('green') + .valueAccessor(function (d) { return d.value.status }) + .group(solvedGroup, "Solved"), + dc.lineChart(statusChart) + .dimension(overallDim) + .valueAccessor(function (d) { return d.value.status }) + .group(mitigatedGroup, "Mitigated"), + dc.lineChart(statusChart) + .dimension(overallDim) + .colors('Crimson') + .valueAccessor(function (d) { return d.value.status }) + .group(mitigatedGroup, "Not identified"), + dc.lineChart(statusChart) + .dimension(overallDim) + .colors('LightGrey') + .valueAccessor(function (d) { return d.value.status }) + .group(riskAcceptedGroup, "Risk accepted") + + ]) // Rendering all charts: d3.selectAll("svg") .attr("width", "90%") .attr("viewbox","0 0 20 20"); dc.renderAll(); + });