Javascript 地点:“, “广告商”:“Acme,Inc.”, “支出”:0.64, “利润”:-0.64, “cpc”:0.05, “rpc”:0, “rpa”:” }] 常量列标题映射={ 日期:“日期”, Affiliated:“Affiliated”, 花:“花

Javascript 地点:“, “广告商”:“Acme,Inc.”, “支出”:0.64, “利润”:-0.64, “cpc”:0.05, “rpc”:0, “rpa”:” }] 常量列标题映射={ 日期:“日期”, Affiliated:“Affiliated”, 花:“花,javascript,d3.js,Javascript,D3.js,地点:“, “广告商”:“Acme,Inc.”, “支出”:0.64, “利润”:-0.64, “cpc”:0.05, “rpc”:0, “rpa”:” }] 常量列标题映射={ 日期:“日期”, Affiliated:“Affiliated”, 花:“花”, 收入:“收入”, 中国共产党:“中国共产党”, RPC:“RPC”, RPA:“RPA”, 利润:“利润”, PM:“profitMargin”, 活动:“活动名称”, 附属公司:“附属公司” }; const headers=Objec

地点:“, “广告商”:“Acme,Inc.”, “支出”:0.64, “利润”:-0.64, “cpc”:0.05, “rpc”:0, “rpa”:” }] 常量列标题映射={ 日期:“日期”, Affiliated:“Affiliated”, 花:“花”, 收入:“收入”, 中国共产党:“中国共产党”, RPC:“RPC”, RPA:“RPA”, 利润:“利润”, PM:“profitMargin”, 活动:“活动名称”, 附属公司:“附属公司” }; const headers=Object.keys(columnHeaderMap); const columns=headers.map(header=>columnHeaderMap[header]); const getHeaderWithColumn=列=>{ for(让标题位于columnHeaderMap中){ if(columnHeaderMap[标题]==列){ 返回头; } } }; ////设置表的区域 d3.选择全部('table')。数据([0])。输入()。追加('table'); var table1=d3。选择(“#table”); 表1.选择全部('thead')。数据([0])。输入()。追加('thead'); var thead=表1。选择('thead'); 表1.选择全部('tbody')。数据([0])。输入()。追加('tbody'); var tbody=表1。选择('tbody'); var pmColorScale=d3.scaleThreshold() .domain([0,20]) .范围([‘红色’、‘绿色’); ////追加标题行 thead.append('tr') .selectAll('th') .数据(标题) .输入() .append('th') .text(函数(列){ 返回列; }) .on('点击')功能(d){ thead.attr('class','header'); const columnName=columnHeaderMap[d]; 如果(排序){ 行排序((a,b)=>{ 如果(d=='PM'){ if(isNaN(a.profitMargin)){ 返回a.profitMargin==0; } if(isNaN(b.profitMargin)){ 返回b.profitMargin==0; } a、 profitMargin=Number.parseFloat(a.profitMargin); b、 profitMargin=Number.parseFloat(b.profitMargin); //将字符串解析为浮点数 //然后进行排序计算 } 返回b[columnHeaderMap[d]{ 如果(d=='PM'){ if(isNaN(a.profitMargin)){ 返回a.profitMargin==0; } if(isNaN(b.profitMargin)){ 返回b.profitMargin==0; } a、 profitMargin=Number.parseFloat(a.profitMargin); b、 profitMargin=Number.parseFloat(b.profitMargin); //将字符串解析为浮点数 //然后进行排序计算 } 返回b[columnHeaderMap[d]>a[columnHeaderMap[d]]?1:-1; }); sortAscending=true; } }); ////为数据中的每个对象创建一行 var rows=tbody.selectAll('tr') .数据(合并) .输入() .append('tr'); ////为每列的每行创建一个单元格 变量单元格=行。选择全部('td') .数据(功能(行){ 返回columns.map(函数(列){ 返回{ 列:getHeaderWithColumn(列), 值:行[列], }; }); }) .输入() .append('td')) .样式(“颜色”,功能(d){ 如果(d.column=='PM'){ 返回pmColorScale(d值); } 如果(d.列==‘利润’){ 如果(d.值<0){ 返回“红色”; } } }).html(函数(d){ percentFormatter=d3.format(“.0%”); dollarFormatter=d3.format($,“”); 如果(d.column=='PM'){ 如果(!isNaN(d值)){ 如果(isNaN(d值)){ d、 value==Number.parseInt(0); } 返回百分比格式化程序(d值/100); } } 如果(d.column===‘支出’| | d.column==‘收入’| | d.column==‘CPC’| | d.column==‘RPC’| | d.column==‘RPA’| | d.column==‘利润’){ 如果(!isNaN(d值)){ 返回dollarFormatter(d.value); } } 返回d值; }); 函数排序(a,b){ 如果(a的类型==“字符串”){ var parseA=format.parse(a); if(parseA){ var dateA=parseA.getDate(); var dateB=format.parse(b).getDate(); 返回日期a>dateB?1:dateA==dateB?0:-1; }否则 返回a.localeCompare(b); }else if(a的类型==“数字”){ 返回a>b1:a==b0:-1; }else if(a的类型==“布尔”){ 返回b?1:a?-1:0; } } //是做总结的时候了 ////这是小计缩减器,因此每个id都有其总计 const summary=merged.reduce(函数(val、acc){
const merged = [{
"date": "2018-10-09",
"Campaign_Name": "Foo - 6480_1925",
"affiliateId": "6480",
"Clicks": 6,
"Conversions": 0,
"Spend": 0.5019512028,
"affiliate": "Y_Foo_6480",
"revenue": 58.22,
"advertiser": "sky",
"spend": 0.5,
"profit": 57.72,
"profitMargin": "99",
"cpc": 0.08,
"rpc": 9.7,
"rpa": ""
}, {
"date": "2018-10-09",
"Campaign_Name": "Bar Mutual - 7157_2020",
"affiliateId": "7157",
"Clicks": 583,
"Conversions": 0,
"Spend": 166.0008698087,
"affiliate": "Y_Bar Mutual_7157",
"revenue": 2.22,
"advertiser": "Bar Mutual Insurance",
"spend": 166,
"profit": -163.78,
"profitMargin": "-7378",
"cpc": 0.28,
"rpc": 0,
"rpa": ""
}, {
"date": "2018-10-09",
"Campaign_Name": "test - Baz Deals - CAN - 4086_1743",
"affiliateId": "4086",
"Clicks": 1,
"Conversions": 0,
"Spend": 0.0108815003,
"affiliate": "Y_Mobile_OMBaz_CAN_4086",
"revenue": "",
"advertiser": "Acme, Inc. ",
"spend": 0.01,
"profit": -0.01,
"cpc": 0.01,
"rpc": 0,
"rpa": ""
}, {
"date": "2018-10-09",
"Campaign_Name": "test - GetStuff - 7191_2133",
"affiliateId": "7191",
"Clicks": 6,
"Conversions": 0,
"Spend": 1.3499999642,
"affiliate": "Y_GetStuff_7191",
"revenue": 0.36,
"advertiser": "Art",
"spend": 1.35,
"profit": -0.99,
"profitMargin": "-275",
"cpc": 0.22,
"rpc": 0.06,
"rpa": ""
}, {
"date": "2018-10-09",
"Campaign_Name": "test - Lawyer - 7275_2165",
"affiliateId": "7275",
"Clicks": 199,
"Conversions": 0,
"Spend": 10.2255493868,
"affiliate": "Y_Lawyer_7275",
"revenue": "",
"advertiser": "Acme, Inc. ",
"spend": 10.23,
"profit": -10.23,
"cpc": 0.06,
"rpc": 0,
"rpa": ""
}, {
"date": "2018-10-09",
"Campaign_Name": "test - NS - New Cars - 4735_2092",
"affiliateId": "4735",
"Clicks": 200,
"Conversions": 34,
"Spend": 59.1212777495,
"affiliate": "Y_Mobile-3B_OMNewCar_4735",
"revenue": 20.1,
"advertiser": "Acme, Inc. ",
"spend": 59.12,
"profit": -39.02,
"profitMargin": "-194",
"cpc": 0.3,
"rpc": 0.1,
"rpa": 0.59
}, {
"date": "2018-10-09",
"Campaign_Name": "test - NS - New Cars - 6586_2092",
"affiliateId": "6586",
"Clicks": 472,
"Conversions": 79,
"Spend": 61.0002093334,
"affiliate": "Y_New Cars_6586",
"revenue": 0.75,
"advertiser": "Acme, Inc. ",
"spend": 61,
"profit": -60.25,
"profitMargin": "-8033",
"cpc": 0.13,
"rpc": 0,
"rpa": 0.01
}, {
"date": "2018-10-09",
"Campaign_Name": "test - NS - New Cars - 6618_2092",
"affiliateId": "6618",
"Clicks": 2,
"Conversions": 1,
"Spend": 0.2018772066,
"affiliate": "Y_New Cars_6618",
"revenue": "",
"advertiser": "Acme, Inc. ",
"spend": 0.2,
"profit": -0.2,
"cpc": 0.1,
"rpc": 0,
"rpa": 0
}, {
"date": "2018-10-09",
"Campaign_Name": "test - NS - New Cars - 7247_1773",
"affiliateId": "7247",
"Clicks": 76,
"Conversions": 7,
"Spend": 13.9912065665,
"affiliate": "Y_New Cars_7247",
"revenue": "",
"advertiser": "Acme, Inc. ",
"spend": 13.99,
"profit": -13.99,
"cpc": 0.18,
"rpc": 0,
"rpa": 0
}, {
"date": "2018-10-09",
"Campaign_Name": "test - NS - New Cars - NSConvLAL - 6594_2092",
"affiliateId": "6594",
"Clicks": 905,
"Conversions": 264,
"Spend": 293.5172631741,
"affiliate": "Y_New Cars_6594",
"revenue": 1.72,
"advertiser": "Acme, Inc. ",
"spend": 293.64,
"profit": -291.8,
"profitMargin": "-16965",
"cpc": 0.32,
"rpc": 0,
"rpa": 0.01
}, {
"date": "2018-10-09",
"Campaign_Name": "test - NS - New Cars - NSConvLAL - 7251_2092",
"affiliateId": "7251",
"Clicks": 202,
"Conversions": 1,
"Spend": 64.9944748056,
"affiliate": "Y_New Cars_7251",
"revenue": "",
"advertiser": "Acme, Inc. ",
"spend": 64.99,
"profit": -64.99,
"cpc": 0.26,
"rpc": 0,
"rpa": 0
}, {
"date": "2018-10-09",
"Campaign_Name": "test - NS - New Cars - Span/Eng - 7165_1773",
"affiliateId": "7165",
"Clicks": 891,
"Conversions": 49,
"Spend": 74.5347691271,
"affiliate": "Y_New Cars_7165",
"revenue": "",
"advertiser": "Acme, Inc. ",
"spend": 74.53,
"profit": -74.53,
"cpc": 0.08,
"rpc": 0,
"rpa": 0
}, {
"date": "2018-10-09",
"Campaign_Name": "test - New Cars - 4713_1875",
"affiliateId": "4713",
"Clicks": 1084,
"Conversions": 326,
"Spend": 64.7100853845,
"affiliate": "Y_New Cars_4713",
"revenue": "",
"advertiser": "Umbrella",
"spend": 64.71,
"profit": -64.71,
"cpc": 0.05,
"rpc": 0,
"rpa": 0
}, {
"date": "2018-10-09",
"Campaign_Name": "test - New Cars - 7259_1875",
"affiliateId": "7259",
"Clicks": 1568,
"Conversions": 173,
"Spend": 51.5844874121,
"affiliate": "Y_New Cars_7259",
"revenue": "",
"advertiser": "Umbrella",
"spend": 51.58,
"profit": -51.58,
"cpc": 0.03,
"rpc": 0,
"rpa": 0
}, {
"date": "2018-10-09",
"Campaign_Name": "test - Destination - 7221_2068",
"affiliateId": "7221",
"Clicks": 75,
"Conversions": 0,
"Spend": 4.9945735649,
"affiliate": "Y_Destination_7221",
"revenue": 1.5,
"advertiser": "L-health",
"spend": 4.99,
"profit": -3.17,
"profitMargin": "-212",
"cpc": 0.06,
"rpc": 0.02,
"rpa": ""
}, {
"date": "2018-10-09",
"Campaign_Name": "test - Product - 7243_1791",
"affiliateId": "7243",
"Clicks": 36,
"Conversions": 0,
"Spend": 1.201965495,
"affiliate": "Y_Product_7243",
"revenue": 0.07,
"advertiser": "Product Tubs",
"spend": 1.2,
"profit": -1.13,
"profitMargin": "-1617",
"cpc": 0.03,
"rpc": 0,
"rpa": ""
}, {
"date": "2018-10-09",
"Campaign_Name": "test - Homewares - 7269_2163",
"affiliateId": "7269",
"Clicks": 11,
"Conversions": 0,
"Spend": 0.5186665021,
"affiliate": "Y_Homewares_7269",
"revenue": "",
"advertiser": "Acme, Inc. ",
"spend": 0.64,
"profit": -0.64,
"cpc": 0.05,
"rpc": 0,
"rpa": ""
}]
const columnHeaderMap = {
            Date: "date",
            AffiliateId: "affiliateId",
            Spend: "spend",
            Revenue: "revenue",
            CPC: "cpc",
            RPC: "rpc",
            RPA: "rpa",
            Profit: "profit",
            PM: "profitMargin",
            Campaign: "Campaign_Name",
            Affiliate: "affiliate"
        };

        const headers = Object.keys(columnHeaderMap);
        const columns = headers.map(header => columnHeaderMap[header]);

        const getHeaderWithColumn = column => {
            for (let header in columnHeaderMap) {
                if (columnHeaderMap[header] === column) {
                    return header;
                }
            }
        };

        // // setup the area for the table
        d3.selectAll('table').data([0]).enter().append('table');
        var table1 = d3.select('#table');

        table1.selectAll('thead').data([0]).enter().append('thead');
        var thead = table1.select('thead');

        table1.selectAll('tbody').data([0]).enter().append('tbody');
        var tbody = table1.select('tbody');

        var pmColorScale = d3.scaleThreshold()
            .domain([0, 20])
            .range(['red', '#FDE541', 'green']);

        //   // append the header row
        thead.append('tr')
            .selectAll('th')
            .data(headers)
            .enter()
            .append('th')
            .text(function (column) {
                return column;
            })
            .on('click', function (d) {
                thead.attr('class', 'header');
                const columnName = columnHeaderMap[d];
                if (sortAscending) {
                    rows.sort((a, b) => {
                        if (d === 'PM') {
                            if (isNaN(a.profitMargin)) {
                                return a.profitMargin == 0;
                            }
                            if (isNaN(b.profitMargin)) {
                                return b.profitMargin == 0;
                            }
                            a.profitMargin = Number.parseFloat(a.profitMargin);
                            b.profitMargin = Number.parseFloat(b.profitMargin);
                            // parse the string into a float
                            // then do the sort calc
                        }
                        return b[columnHeaderMap[d]] < a[columnHeaderMap[d]] ? 1 : -1;
                    });
                    sortAscending = false;
                } else {
                    rows.sort((a, b) => {
                        if (d === 'PM') {
                            if (isNaN(a.profitMargin)) {
                                return a.profitMargin == 0;
                            }
                            if (isNaN(b.profitMargin)) {
                                return b.profitMargin == 0;
                            }
                            a.profitMargin = Number.parseFloat(a.profitMargin);
                            b.profitMargin = Number.parseFloat(b.profitMargin);

                            // parse the string into a float
                            // then do the sort calc
                        }
                        return b[columnHeaderMap[d]] > a[columnHeaderMap[d]] ? 1 : -1;
                    });
                    sortAscending = true;
                }

            });

        //  // create a row for each object in the data
        var rows = tbody.selectAll('tr')
            .data(merged)
            .enter()
            .append('tr');

        //   // create a cell in each row for each column
        var cells = rows.selectAll('td')
            .data(function (row) {
                return columns.map(function (column) {
                    return {
                        column: getHeaderWithColumn(column),
                        value: row[column],
                    };
                });
            })
            .enter()
            .append('td')
            .style("color", function (d) {
                if (d.column === 'PM') {
                    return pmColorScale(d.value);
                }

                if (d.column === 'Profit') {
                    if (d.value < 0) {
                        return "red";
                    }
                }
            }).html(function (d) {
                percentFormatter = d3.format(".0%");
                dollarFormatter = d3.format("$,");
                if (d.column === 'PM') {
                    if (!isNaN(d.value)) {
                        if (isNaN(d.value)) {
                            d.value === Number.parseInt(0);
                        }
                        return percentFormatter(d.value / 100);
                    }
                }
                if (d.column === 'Spend' || d.column === 'Revenue' || d.column === 'CPC' || d.column === 'RPC' || d.column === 'RPA' || d.column === 'Profit') {
                    if (!isNaN(d.value)) {
                        return dollarFormatter(d.value);
                    }
                }
                return d.value;
            });

        function sort(a, b) {
            if (typeof a == "string") {
                var parseA = format.parse(a);
                if (parseA) {
                    var dateA = parseA.getDate();
                    var dateB = format.parse(b).getDate();
                    return dateA > dateB ? 1 : dateA == dateB ? 0 : -1;
                } else
                    return a.localeCompare(b);
            } else if (typeof a == "number") {
                return a > b ? 1 : a == b ? 0 : -1;
            } else if (typeof a == "boolean") {
                return b ? 1 : a ? -1 : 0;
            }
        }

        // Time to make the summary 

        // // This is a subtotal reducer so each id has its total
        const summary = merged.reduce(function (val, acc) {
            if (!val[acc.affiliateId]) val[acc.affiliateId] = {
                affiliateId: acc.affiliateId,
                Spend: 0,
                revenue: 0,
                profit: 0,
                profitMargin: 0,
                Clicks: 0,
                Conversions: 0
            };
            val[acc.affiliateId].Clicks += Number.parseFloat(acc.Clicks);
            val[acc.affiliateId].Conversions += Number.parseFloat(acc.Conversions);
            val[acc.affiliateId].Spend += Number.parseFloat(acc.Spend);
            val[acc.affiliateId].revenue += Number.parseFloat(acc.revenue);
            val[acc.affiliateId].profit += Number.parseFloat(acc.profit);
            val[acc.affiliateId].Campaign_Name = acc.Campaign_Name;
            val[acc.affiliateId].affiliate = acc.affiliate;
            val[acc.affiliateId].advertiser = acc.advertiser;

            return val;
        }, {});
        // console.log(summary); // returns the array with the accumulators and ids as keys, after which I then I set to an array to look like typical JSON
          const summaryArr = [];
        for (var entry in summary) {
            // console.log(sum[entry]);
            summaryArr.push(summary[entry]);
        }

        }

    }
function addCells ( selection ) {
// create a cell in each row for each column
  selection.selectAll('td')
  .data(function(row) {
    return columns.map(function(column) {
      return {
        column: getHeaderWithColumn(column),
        value: row[column],
      };
    });
  })
  .enter()
  .append('td')
  .style("color", function(d) {
    if (d.column === 'PM') {
      return pmColorScale(d.value);
    }

    if (d.column === 'Profit') {
      if (d.value < 0) {
        return "red";
      }
    }
  }).html(function(d) {
    percentFormatter = d3.format(".0%");
    dollarFormatter = d3.format("$,");
    if (d.column === 'PM') {
      if (!isNaN(d.value)) {
        if (isNaN(d.value)) {
          d.value === Number.parseInt(0);
        }
        return percentFormatter(d.value / 100);
      }
    }
    if (d.column === 'Spend' || d.column === 'Revenue' || d.column === 'CPC' || d.column === 'RPC' || d.column === 'RPA' || d.column === 'Profit') {
      if (!isNaN(d.value)) {
        return dollarFormatter(d.value);
      }
    }
    return d.value;
  });
}
const summary = merged.reduce(function(val, acc) {
  if (!val[acc.affiliateId]) val[acc.affiliateId] = {
    affiliateId: acc.affiliateId,
    Spend: 0,
    revenue: 0,
    profit: 0,
    profitMargin: 0,
    Clicks: 0,
    Conversions: 0
  };
  val[acc.affiliateId].Clicks += Number.parseFloat(acc.Clicks);
  val[acc.affiliateId].Conversions += Number.parseFloat(acc.Conversions);
  val[acc.affiliateId].Spend += Number.parseFloat(acc.Spend);
  val[acc.affiliateId].revenue += Number.parseFloat(acc.revenue);
  val[acc.affiliateId].profit += Number.parseFloat(acc.profit);
  val[acc.affiliateId].Campaign_Name = acc.Campaign_Name;
  val[acc.affiliateId].affiliate = acc.affiliate;
  val[acc.affiliateId].advertiser = acc.advertiser;

  return val;
}, {});
const nested = d3.nest()
.key( d => d.affiliateId )
.entries(merged)
.map( d => { d.header = summary[d.key]; return d } );
{key: "6480", 
 values: [Array], // rows with affiliateId 6480 
 header: Object   // collated data on 6480 from `summary`
}
var tbody = table1.selectAll('tbody')
  .data(nested)
  .enter()
  .append('tbody');
var summaryRow = tbody
  .selectAll('tr.summary')
  .data(function(d) { return [d.header] })
  .enter()
  .append('tr')
  .classed('summary',true)
addCells(summary)
var rows = tbody.selectAll('tr.entry')
  .data(d => {
    return d.values
  })
  .enter()
  .append('tr')
  .classed('entry', true)

addCells(rows);