123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- /**
- * TraCINg-Server - Gathering and visualizing cyber incidents on the world
- *
- * Copyright 2013 Matthias Gazzari, Annemarie Mattmann, André Wolski
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- var detailChartType = "typeDate";
- /*
- * queries data, filters it, updates the chart
- *
- * options: object
- * - chart: reference to a highcharts Chart
- * - name: string, name of the data that should be displayed
- * - detail: boolean, whether to fetch detailed data or just data for the master chart (optional, default: false)
- */
- function updateChart(options){
- var rawSeries;
- var title, subtitle, xTitle, yTitle;
-
- // get the chart and delete it from options
- var chart = options.chart;
- delete options.chart;
-
- options.filter = filter.getFilter();
-
- // fetch the series
- if(options.detail){
- options.detailChartType = detailChartType;
-
- // patch start and end into the filter
- options.filter["start"] = currentStartDate;
- options.filter["end"] = currentEndDate;
-
-
- if(detailChartType == "typeDate"){
- options.pie = true;
-
- title = {text: "Types of Incidents"};
- subtitle = {text: "per day"};
- yTitle = {text: "Incidents per day"};
- }
- else if(detailChartType == "countryDate"){
- options.pie = true;
-
- title = {text: "Source countries"};
- subtitle = {text: "per day"};
- yTitle = {text: "Incidents per day"};
- }
- else{
- console.log("error: unknown type: " + detailChartType);
- return;
- }
- }
- else{
- // nothing to do..
- }
-
- // some formatting of the chart
- if(title || subtitle)
- chart.setTitle(title, subtitle);
- if(xTitle)
- chart.xAxis[0].setTitle(xTitle);
- if(yTitle)
- chart.yAxis[0].setTitle(yTitle);
-
- chart.showLoading("loading..");
-
- socket.emit("getStatistics", options, function(data){
- console.log("getStatistics returned: ", data);
-
- if(!data || data.length == 0){
- chart.showLoading("No data for that selection!");
- return;
- }
- // filter the series
- var chartSeries = createChartSeries(data, options);
-
- // display the series
- setChartData(chart, chartSeries);
- });
- }
- /*
- * setChartData
- * removes all series from a chart and adds the new series
- *
- * chart: reference to a highcharts Chart
- * data: array of series to be added
- */
- function setChartData(chart, data){
- var oldLenght = chart.series.length;
- // add new series
- for(var i = 0; i < data.length; i++){
- chart.addSeries(data[i], false); // false: do not redraw
- }
-
- chart.redraw();
- // remove old series
- for(var count = 0; count < oldLenght; count++){
- chart.series[0].remove(false); // do not redraw
- }
-
- chart.hideLoading();
- chart.redraw();
- $(".highcharts-legend-item > span").each(function(i, el){el.onclick = null;});
- }
- /*
- * createChartSeries
- * creates series for the chart from the given series, also calculates the pie serie (if options.pie is true)
- *
- * arguments:
- * * series: array of all series that should be displayed
- * * options: optional object of options:
- * - pie: boolean if the last serie is a pie
- */
- function createChartSeries(series, options){
- console.log("createChartSeries", series, options);
-
- // store here the data
- var result = [];
-
- var pie;
- if(options.pie){
- pie = {
- type: "pie",
- name: "Total incidents",
- center: [160, 55],
- size: 100,
- showInLegend: false,
- data: [], // the data is calculated below
- };
- }
-
- // for each serie
- for(var i = 0; i < series.length; i++){
- var c = series[i];
-
- function getColor(i){
- //return Highcharts.getOptions().colors[i];
-
- if(i % 8 == 0)
- return "#0000FF"; // blue
- else if(i % 8 == 1)
- return "#FF0000"; // red
- else if(i % 8 == 2)
- return "#00FF00"; // green
- else if(i % 8 == 3)
- return "#FFFF00"; // yellow
- else if(i % 8 == 4)
- return "#FF00FF"; // magenta
- else if(i % 8 == 5)
- return "#00FFFF"; // cyan
- else if(i % 8 == 6)
- return "#FF7F00"; // orange
- else if(i % 8 == 7)
- return "#808080"; // grey
- /*else if(i % 9 == 8)
- return "#964B00"; // brown*/
-
- }
- // add the serie to the result
- result.push({name: c.name, data: c.data, color: getColor(i)});
-
-
- if(options.pie){
- var sum = 0;
-
- // for each entry of the serie
- for(var j = 0; j < c.data.length; j++){
- // sum the data of this serie for the pie
- sum += c.data[j][1];
- }
-
- // add the summed serie to the pie
- pie.data.push({name: c.name, y: sum, color: getColor(i)});
- }
- }
-
- if(options.pie){
- // add the pie to the result
- result.push(pie);
- }
-
- return result;
- }
- // initial timespan for the detailChart
- var defaultEndDate = Date.now();
- var defaultStartDate = defaultEndDate - (2 * 7 * 24 * 60 * 60 * 1000); // two weeks ago
- var currentStartDate = defaultStartDate;
- var currentEndDate = defaultEndDate;
- var detailChart, masterChart;
- // detailed statistics chart
- function createDetailChart(masterChart) {
- detailChart = $('#chartdivdetail').highcharts({
- chart: {
- type: 'area'
- },
- xAxis: {
- type: 'datetime'
- },
- legend: {useHTML: true},
- plotOptions: {
- area: {
- stacking: 'normal',
- lineColor: '#666666',
- lineWidth: 1,
- marker: {
- lineWidth: 1,
- lineColor: '#666666'
- }
- }
- },
- tooltip: {
- //formatter: function() {
- // return false;
- //}
- },
- }).highcharts();
-
- updateChart({
- chart: detailChart,
- detail: true,
- });
- }
- // timeline chart
- function createMasterChart(){
- masterChart = $("#chartdivmaster").highcharts({
- title: {text: null},
- reflow: false,
- borderWidth: 0,
- chart: {
- type: 'area',
- events: {
- // listen to the selection event on the master chart to update the detail chart
- selection: function(event) {
- // get the selection
- var extremesObject = event.xAxis[0];
- var min = extremesObject.min;
- var max = extremesObject.max;
-
- currentStartDate = min;
- currentEndDate = max;
-
- // select and filter data for the detailChart and update it
- updateChart({
- chart: detailChart,
- detail: true,
- });
-
- // move the plot band to reflect the new detail span
- var xAxis = this.xAxis[0];
- xAxis.removePlotBand('mask');
- xAxis.addPlotBand({
- id: 'mask',
- from: min,
- to: max,
- color: 'rgba(255, 144, 0, 0.6)' // #FF9000; alpha = 60%
- });
-
- // TODO: for what is the return value?
- return false;
- }
- },
- zoomType: 'x',
- },
- xAxis: {
- type: 'datetime',
- plotBands: [{
- id: 'mask',
- from: defaultStartDate,
- to: defaultEndDate,
- color: 'rgba(255, 144, 0, 0.6)'
- }],
- },
- yAxis: {
- gridLineWidth: 0,
- title: {text: null},
- labels: {enabled: false},
- },
- legend: {enabled: false},
- credits: {enabled: false},
- tooltip: {
- formatter: function() {
- return false;
- }
- },
- plotOptions: {
- series: {
- fillColor: {
- linearGradient: [0, 0, 0, 70],
- stops: [
- [0, '#4572A7'],
- [1, 'rgba(0,0,0,0)']
- ]
- },
- lineWidth: 1,
- marker: {
- enabled: false
- },
- shadow: false,
- states: {
- hover: {
- lineWidth: 1
- }
- },
- enableMouseTracking: false
- }
- },
- }, function(masterChart){
- createDetailChart(masterChart);
- }).highcharts();
-
- updateChart({
- chart: masterChart,
- detail: false,
- });
- }
- var createdCharts = false;
- /*
- * create Chart container and objects if not done
- * returns if it created or not
- */
- function createCharts(){
- if(!createdCharts){
- createdCharts = true;
- var container = $('#stats');
- container.append("<div id='chartdivdetail' class='chart'></div>");
- container.append("<div id='chartdivmaster' class='chart' style='height: 100px;' onHelpActive='help-border'></div><span class='help-block'>Click and drag the mouse across the above timeline to choose a timespan.</span>");
- createMasterChart();
- return true;
- }
- return false;
- }
- function loadStats(detailType, updateMaster){
- if(detailType)
- detailChartType = detailType;
-
- var created = createCharts();
- if(!created){ // createCharts loads the charts with the correct data; if there are already charts we need to update them
- updateChart({
- chart: detailChart,
- detail: true,
- });
-
- if(updateMaster){
- updateChart({
- chart: masterChart,
- detail: false,
- });
- }
- }
- }
- // called when the filter was updated
- function filterUpdateStats(){
- loadStats(null, true);
- }
|