Sales V Sliced Cross Report

Sales v sliced cross reports can be useful for tracking the performance of individual salespeople or product lines, identifying trends in consumer behavior, and determining overall growth or decline in revenue.

Description
app.vue
index.html
Copy to CodeMine
Open the demo in new window can open the designer

How to open desgnr

You can use the ‘Group' and 'Summary’ cell types to generate the sales v sliced report in the following steps.

  • Define the sales table in the DataManager.
  • Set the style for the template.
  • Bind the data column to the template and use the ‘Group' and ‘Summary’ cell types, and use both ‘Horizontal’ and 'Vertical’ spill directions.
const spread = new GC.Spread.Sheets.Workbook('ss', { sheetCount: 1 });
spread.options.scrollByPixel = true;
spread.options.scrollbarMaxAlign = true;
const records = [
    ['East', 'John', 'Fruits', 'Banana', 180],
    ['East', 'Mike', 'Fruits', 'Banana', 200],
    ['East', 'Emma', 'Fruits', 'Banana', 210],
    ['East', 'Sophia', 'Fruits', 'Banana', 316],
    ['East', 'Jennifer', 'Fruits', 'Banana', 130],
    ['North', 'Kristen', 'Fruits', 'Banana', 410.0],
    ['North', 'Mia', 'Fruits', 'Banana', 290.0],
    ['North', 'Bella', 'Fruits', 'Banana', 342.0],
    ['North', 'Eva', 'Fruits', 'Banana', 214.0],
    ['East', 'John', 'Fruits', 'Strawberry', 230.0],
    ['East', 'Mike', 'Fruits', 'Strawberry', 641.0],
    ['East', 'Emma', 'Fruits', 'Strawberry', 234.0],
    ['East', 'Sophia', 'Fruits', 'Strawberry', 625.0],
    ['East', 'Jennifer', 'Fruits', 'Strawberry', 241.0],
    ['North', 'Kristen', 'Fruits', 'Strawberry', 195.0],
    ['North', 'Mia', 'Fruits', 'Strawberry', 569.0],
    ['North', 'Bella', 'Fruits', 'Strawberry', 698.0],
    ['North', 'Eva', 'Fruits', 'Strawberry', 214.0],
    ['East', 'John', 'Fruits', 'Watermelon', 147.0],
    ['East', 'Mike', 'Fruits', 'Watermelon', 489.0],
    ['East', 'Emma', 'Fruits', 'Watermelon', 347.0],
    ['East', 'Sophia', 'Fruits', 'Watermelon', 652.0],
    ['East', 'Jennifer', 'Fruits', 'Watermelon', 471.0],
    ['North', 'Kristen', 'Fruits', 'Watermelon', 287.0],
    ['North', 'Mia', 'Fruits', 'Watermelon', 349.0],
    ['North', 'Bella', 'Fruits', 'Watermelon', 163.0],
    ['North', 'Eva', 'Fruits', 'Watermelon', 841.0],
    ['East', 'John', 'Snack', 'Chips', 292.0],
    ['East', 'Mike', 'Snack', 'Chips', 514.0],
    ['East', 'Emma', 'Snack', 'Chips', 256.0],
    ['East', 'Sophia', 'Snack', 'Chips', 148.0],
    ['East', 'Jennifer', 'Snack', 'Chips', 486.0],
    ['North', 'Kristen', 'Snack', 'Chips', 285.0],
    ['North', 'Mia', 'Snack', 'Chips', 741.0],
    ['North', 'Bella', 'Snack', 'Chips', 249.0],
    ['North', 'Eva', 'Snack', 'Chips', 105.0],
    ['East', 'John', 'Snack', 'Cookie', 554.0],
    ['East', 'Mike', 'Snack', 'Cookie', 311.0],
    ['East', 'Emma', 'Snack', 'Cookie', 186.0],
    ['East', 'Sophia', 'Snack', 'Cookie', 654.0],
    ['East', 'Jennifer', 'Snack', 'Cookie', 247.0],
    ['North', 'Kristen', 'Snack', 'Cookie', 143.0],
    ['North', 'Mia', 'Snack', 'Cookie', 617.0],
    ['North', 'Bella', 'Snack', 'Cookie', 214.0],
    ['North', 'Eva', 'Snack', 'Cookie', 324.0],
];
const columns = ['Region', 'Salesman', 'ProductType', 'Product', 'Sales'];
const salesTable = spread.dataManager().addTable('Sales', {
    data: records.map((x) => {
        const record = {};
        columns.forEach((c, i) => record[c] = x[i]);
        return record;
    })
});

salesTable.fetch().then(() => {
    const reportSheet = spread.addSheetTab(0, 'report1', GC.Spread.Sheets.SheetType.reportSheet);
    const templateSheet = reportSheet.getTemplate();

    // set style for the template
    templateSheet.defaults.colWidth = 100;
    templateSheet.defaults.rowHeight = 30;
    templateSheet.setColumnWidth(0, 200);
    const headerStyle = new GC.Spread.Sheets.Style();
    headerStyle.backColor = '#90CAF9';
    headerStyle.foreColor = '#424242';
    headerStyle.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
    headerStyle.vAlign = GC.Spread.Sheets.VerticalAlign.center;
    headerStyle.font = '12px Maine';
    templateSheet.getRange('A1:D8').setStyle(headerStyle);
    [2, 4, 6].forEach(r => {
        const newStyle = templateSheet.getStyle(r, 0).clone();
        newStyle.hAlign = GC.Spread.Sheets.HorizontalAlign.left;
        newStyle.textIndent = 1;
        templateSheet.setStyle(r, 0, newStyle);
    });
    [1, 2].forEach(c => {
        const newStyle = templateSheet.getStyle(1, c).clone();
        newStyle.backColor = '#B3E5FC';
        templateSheet.setStyle(1, c, newStyle);
    });
    const newStyle = templateSheet.getStyle(0, 1).clone();
    newStyle.backColor = '#B3E5FC';
    templateSheet.setStyle(0, 1, newStyle);
    const border = new GC.Spread.Sheets.LineBorder('#E0E0E0', 1);
    ['#C8E6C9', '#A5D6A7', '#81C784'].forEach((bg, r) => {
        r = (r * 2) + 3;
        const newStyle = templateSheet.getStyle(r, 0).clone();
        newStyle.backColor = bg;
        templateSheet.setStyle(r, 0, newStyle);

        ['#FFCC80', undefined, '#FFA726'].forEach((x, c) => {
            const newStyle1 = templateSheet.getStyle(r, c + 1).clone();
            newStyle1.backColor = x;
            if (!x) {
                newStyle1.borderBottom = border;
                newStyle1.borderTop = border;
                newStyle1.borderLeft = border;
                newStyle1.borderRight = border;
            }
            templateSheet.setStyle(r, c + 1, newStyle1);
        })
    });

    [[0, 0, 2, 1], [0, 1, 2, 1], [0, 3, 2, 1], [2, 0, 1, 4], [4, 0, 1, 4], [6, 0, 1, 4]].forEach(x => templateSheet.addSpan(...x));
    templateSheet.setValue(0, 0, 'Category');
    templateSheet.setValue(0, 2, 'Include');
    templateSheet.setValue(0, 3, 'Total');
    templateSheet.setValue(2, 0, 'Product Sales');
    templateSheet.setValue(4, 0, 'Product Type Sales');
    templateSheet.setValue(6, 0, 'Total Sales');
    templateSheet.setValue(7, 0, 'Total');

    // binding for the template
    templateSheet.setTemplateCell(0, 1, {
        type: 'Group',
        binding: 'Sales[Region]',
        spillDirection: 'Horizontal',
        showCollapseButton: true,
    });
    templateSheet.setTemplateCell(1, 2, {
        type: 'Group',
        binding: 'Sales[Salesman]',
        spillDirection: 'Horizontal',
        context: {
            horizontal: 'B1',
        },
    });
    ['Product', 'ProductType', ''].forEach((x, r) => {
        r = (r * 2) + 3;
        if (x) {
            templateSheet.setTemplateCell(r, 0, {
                type: 'Group',
                binding: `Sales[${x}]`,
            });
        }

        [1, 2, 3].forEach(c => {
            templateSheet.setTemplateCell(r, c, {
                type: 'Summary',
                aggregate: 'Sum',
                binding: 'Sales[Sales]',
                context: {
                    horizontal: c === 1
                        ? 'B1'
                        : c === 2 ? 'C2' : 'Default',
                },
            });
        });
    });
    [2, 4, 6].forEach(r => {
        templateSheet.setTemplateCell(r, 0, {
            type: 'Static',
            context: {
                horizontal: 'None',
            },
        });
    });

    reportSheet.refresh();
});
Open the demo in new window can open the designer You can use the ‘Group' and 'Summary’ cell types to generate the sales v sliced report in the following steps. Define the sales table in the DataManager. Set the style for the template. Bind the data column to the template and use the ‘Group' and ‘Summary’ cell types, and use both ‘Horizontal’ and 'Vertical’ spill directions.
<template> <gc-spread-sheets-designer class="demo" v-if="showDesigner" @designerInitialized="initDesigner" /> <gc-spread-sheets class="demo" v-else @workbookInitialized="initSpread" /> </template> <script setup> import GC from '@mescius/spread-sheets'; import '@mescius/spread-sheets-print'; import '@mescius/spread-sheets-shapes'; import '@mescius/spread-sheets-charts'; import '@mescius/spread-sheets-reportsheet-addon'; import '@mescius/spread-sheets-tablesheet'; import '@mescius/spread-sheets-ganttsheet'; import '@mescius/spread-sheets-formula-panel'; import '@mescius/spread-sheets-vue'; import '@mescius/spread-sheets-designer-resources-en'; import '@mescius/spread-sheets-designer-vue'; import { ref } from 'vue'; import '$DEMOROOT$/spread/source/js/react_vue/license.js'; import { registerlic } from '$DEMOROOT$/spread/source/js/designer/react_vue/license.js'; registerlic(GC); const showDesigner = top === window; const spreadRef = ref(null); const designerRef = ref(null); async function initDesigner(designer) { designerRef.value = designer; await initSpread(designer.getWorkbook()); designer.refresh(); } async function initSpread(spread) { spreadRef.value = spread; spread.suspendPaint(); spread.setSheetCount(1); const loadingTip = addLoadingTip(); const res = await fetch('$DEMOROOT$/en/sample/features/report-sheet/showcase/cross-report/sales-v-sliced-cross-report/spread.json'); await spread.fromJSON(await res.json()); loadingTip.remove(); spread.resumePaint(); } function addLoadingTip() { const div = document.createElement('div'); div.style.position = 'absolute'; div.style.inset = '0'; div.style.display = 'flex'; div.style.alignItems = 'center'; div.style.justifyContent = 'center'; div.style.background = 'white'; div.style.zIndex = '100'; div.textContent = 'Loading data from server ...'; document.body.appendChild(div); return div; } </script> <style scoped> body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; } #app { height: 100%; } .demo { width: 100%; height: 100%; overflow: hidden; } </style>
<!DOCTYPE html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>SpreadJS VUE</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/vue3/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/vue3/node_modules/@mescius/spread-sheets-designer/styles/gc.spread.sheets.designer.min.css"> <script src="$DEMOROOT$/en/vue3/node_modules/systemjs/dist/system.src.js"></script> <script src="./systemjs.config.js"></script> <script src="./compiler.js" type="module"></script> <script> System.import("./src/app.js"); </script> </head> <body> <div id="app"></div> </body> </html>
(function (global) { SystemJS.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, packageConfigPaths: [ './node_modules/*/package.json', "./node_modules/@mescius/*/package.json", "./node_modules/@babel/*/package.json", "./node_modules/@vue/*/package.json" ], map: { 'vue': "npm:vue/dist/vue.esm-browser.js", 'tiny-emitter': 'npm:tiny-emitter/index.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', "systemjs-babel-build": "npm:systemjs-plugin-babel/systemjs-babel-browser.js", '@mescius/spread-sheets-designer-resources-en': 'npm:@mescius/spread-sheets-designer-resources-en/index.js', '@mescius/spread-sheets-designer-vue': 'npm:@mescius/spread-sheets-designer-vue/index.js', '@mescius/spread-sheets-designer': 'npm:@mescius/spread-sheets-designer/index.js', '@mescius/spread-excelio': 'npm:@mescius/spread-excelio/index.js', '@mescius/spread-sheets-barcode': 'npm:@mescius/spread-sheets-barcode/index.js', '@mescius/spread-sheets-charts': 'npm:@mescius/spread-sheets-charts/index.js', '@mescius/spread-sheets-languagepackages': 'npm:@mescius/spread-sheets-languagepackages/index.js', '@mescius/spread-sheets-print': 'npm:@mescius/spread-sheets-print/index.js', '@mescius/spread-sheets-pdf': 'npm:@mescius/spread-sheets-pdf/index.js', '@mescius/spread-sheets-shapes': 'npm:@mescius/spread-sheets-shapes/index.js', '@mescius/spread-sheets-io': 'npm:@mescius/spread-sheets-io/index.js', '@mescius/spread-sheets-reportsheet-addon': 'npm:@mescius/spread-sheets-reportsheet-addon/index.js', '@mescius/spread-sheets-tablesheet': 'npm:@mescius/spread-sheets-tablesheet/index.js', '@mescius/spread-sheets-ganttsheet': 'npm:@mescius/spread-sheets-ganttsheet/index.js', '@mescius/spread-sheets-formula-panel': 'npm:@mescius/spread-sheets-formula-panel/index.js', '@mescius/spread-sheets-vue': 'npm:@mescius/spread-sheets-vue/index.js', '@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js', }, meta: { '*.css': { loader: 'systemjs-plugin-css' }, '*.vue': { loader: "../plugin-vue/index.js" } } }); })(this);