List of all demos

Vue Pivot Table: live data update

Update real-time data in your Vue pivot table tool.


    <template>
      <Pivot
        ref="pivot"
        height="450"
        v-bind:report="report"
        v-bind:customizeCell="customizeCell"
        v-bind:reportcomplete="onReportComplete"
      />
    </template>
    
    <script>
    import Pivot from "vue-flexmonster/vue3";
    import "flexmonster/flexmonster.css";
    
    const currency_data = {
      "base": "EUR",
      "date": "2019-02-25",
      "rates": {
        "AED": 4.1643,
        "AFN": 84.5209,
        "ALL": 124.678,
        "AMD": 554.211,
        "ANG": 2.046,
        "AOA": 356.192,
        "ARS": 44.171,
        "AUD": 1.581,
        "AWG": 2.041317,
        "AZN": 1.933087,
        "BAM": 1.951296,
        "BBD": 2.258204,
        "BDT": 95.400537,
        "BGN": 1.954755,
        "BHD": 0.427422,
        "BIF": 2069.094139,
        "BMD": 1.13375,
        "BND": 1.531244,
        "BOB": 7.835064,
        "BRL": 4.233539,
        "BSD": 1.13392,
        "BTC": 0.000295,
        "BTN": 80.316392,
        "BWP": 11.923596,
        "BYN": 2.421119,
        "BYR": 22221.50418,
        "BZD": 2.285526,
        "CAD": 1.495887,
        "CDF": 1849.145964,
        "CHF": 1.135042,
        "CLF": 0.028398,
        "CLP": 736.823969,
        "CNY": 7.584107,
        "COP": 3513.832036,
        "CRC": 689.48953,
        "CUC": 1.13375,
        "CUP": 30.044381,
        "CVE": 110.535542,
        "CZK": 25.640665,
        "DJF": 201.49075,
        "DKK": 7.460864,
        "DOP": 57.407458,
        "DZD": 134.485261,
        "EGP": 19.893917,
        "ERN": 17.005966,
        "ETB": 32.447734,
        "EUR": 1,
        "FJD": 2.411826,
        "FKP": 0.861639,
        "GBP": 0.86868,
        "GEL": 3.032784,
        "GGP": 0.86856,
        "GHS": 6.06658,
        "GIP": 0.861639,
        "GMD": 56.182966,
        "GNF": 10464.51457,
        "GTQ": 8.747903,
        "GYD": 237.157986,
        "HKD": 8.89842,
        "HNL": 27.816591,
        "HRK": 7.429808,
        "HTG": 92.849617,
        "HUF": 317.886543,
        "IDR": 15850.394857,
        "ILS": 4.089607,
        "IMP": 0.86856,
        "INR": 80.331833,
        "IQD": 1350.296504,
        "IRR": 47736.552753,
        "ISK": 136.02732,
        "JEP": 0.86856,
        "JMD": 148.419352,
        "JOD": 0.80406,
        "JPY": 125.963013,
        "KES": 113.589954,
        "KGS": 78.965538,
        "KHR": 4529.332142,
        "KMF": 491.704489,
        "KPW": 1020.424717,
        "KRW": 1265.627953,
        "KWD": 0.344205,
        "KYD": 0.944936,
        "KZT": 426.652611,
        "LAK": 9733.813543,
        "LBP": 1710.545227,
        "LKR": 203.779877,
        "LRD": 182.675544,
        "LSL": 15.725492,
        "LTL": 3.347669,
        "LVL": 0.685794,
        "LYD": 1.570208,
        "MAD": 10.837289,
        "MDL": 19.423471,
        "MGA": 4031.615903,
        "MKD": 61.43116,
        "MMK": 1729.705727,
        "MNT": 2986.538471,
        "MOP": 9.166594,
        "MRO": 404.74865,
        "MUR": 38.615273,
        "MVR": 17.516396,
        "MWK": 825.954017,
        "MXN": 21.649865,
        "MYR": 4.612319,
        "MZN": 70.921734,
        "NAD": 15.782157,
        "NGN": 410.417537,
        "NIO": 37.078618,
        "NOK": 9.766108,
        "NPR": 128.448243,
        "NZD": 1.647271,
        "OMR": 0.4365,
        "PAB": 1.133807,
        "PEN": 3.747606,
        "PGK": 3.819774,
        "PHP": 58.821793,
        "PKR": 158.464073,
        "PLN": 4.336652,
        "PYG": 6911.795951,
        "QAR": 4.128268,
        "RON": 4.763788,
        "RSD": 118.181746,
        "RUB": 74.335013,
        "RWF": 1003.368939,
        "SAR": 4.252014,
        "SBD": 9.242728,
        "SCR": 15.486461,
        "SDG": 53.994863,
        "SEK": 10.580947,
        "SGD": 1.530674,
        "SHP": 1.49757,
        "SLL": 53943.834921,
        "SOS": 657.574824,
        "SRD": 8.455556,
        "STD": 23866.121798,
        "SVC": 9.921339,
        "SYP": 583.881104,
        "SZL": 15.725163,
        "THB": 35.46594,
        "TJS": 10.692378,
        "TMT": 3.968126,
        "TND": 3.460321,
        "TOP": 2.560744,
        "TRY": 6.012391,
        "TTD": 7.693459,
        "TWD": 34.887776,
        "TZS": 2658.758853,
        "UAH": 30.532255,
        "UGX": 4161.423158,
        "USD": 1.13375,
        "UYU": 37.118517,
        "UZS": 9529.170292,
        "VEF": 11.323328,
        "VND": 26322.278702,
        "VUV": 129.088049,
        "WST": 2.957815,
        "XAF": 654.457601,
        "XAG": 0.071336,
        "XAU": 0.000855,
        "XCD": 3.064017,
        "XDR": 0.813828,
        "XOF": 662.110657,
        "XPF": 119.609776,
        "YER": 283.758118,
        "ZAR": 15.681917,
        "ZMK": 10205.116639,
        "ZMW": 13.549464,
        "ZWL": 365.470062,
      },
    };
    
    const valids = ["EUR", "JPY", "CZK", "DKK", "GBP", "HUF", "UAH", "LTL", "LVL",
      "PLN", "RON", "SEK", "CHF", "NOK", "HRK", "RUB", "TRY", "AUD", "BRL", "CAD",
      "CNY", "HKD", "IDR", "ILS", "INR", "KRW", "MXN", "MYR", "NZD", "PHP", "SGD",
      "THB", "ZAR", "ISK"];
    
    export default {
      name: "PivotComponent",
      components: {
        Pivot,
      },
      data() {
        return {
          report: {
            dataSource: {
              type: "json",
              data: [
                {
                  "ID": "ISK",
                  "Currency": "ISK",
                  "Bid Rate": 136.02732,
                  "Ask Rate": 136.02732,
                },
              ],
              mapping: {
                "ID": {
                  type: "id",
                },
                "Currency": {
                  type: "string",
                  caption: "Currency",
                },
                "Bid Rate": {
                  type: "number",
                },
                "Ask Rate": {
                  type: "number",
                },
              },
            },
            slice: {
              rows: [
                {
                  uniqueName: "Currency",
                  sort: "asc",
                },
              ],
              columns: [
                {
                  uniqueName: "[Measures]",
                },
              ],
              measures: [
                {
                  uniqueName: "Bid Rate",
                  aggregation: "sum",
                  format: "rate_format",
                },
                {
                  uniqueName: "Ask Rate",
                  aggregation: "sum",
                  format: "rate_format",
                },
              ],
              flatOrder: ["Bid Rate", "Currency", "Ask Rate"],
            },
            options: {
              grid: {
                type: "flat",
                showFilter: false,
                showHeaders: false,
                showTotals: "off",
                showGrandTotals: "off",
              },
              configuratorButton: false,
              drillThrough: false,
            },
            conditions: [
              {
                formula: "if(#updateDifference < 0, 'fm-updated-cell-down', 'fm-updated-cell-up')",
              },
            ],
            formats: [
              {
                name: "rate_format",
                decimalPlaces: 4,
                textAlign: "left",
                thousandsSeparator: ",",
                decimalSeparator: ".",
              },
            ],
            tableSizes: {
              columns: [
                {
                  tuple: ["Currency"],
                  width: 200,
                },
                {
                  tuple: ["Bid Rate"],
                  width: 200,
                },
                {
                  tuple: ["Ask Rate"],
                  width: 200,
                },
              ],
            },
          },
          dataset: [],
        };
      },
      methods: {
        getData() {
          let rates = currency_data.rates;
    
          Object.entries(rates).forEach(([key, value]) => {
            let record = {};
            record["ID"] = key;
            record["Currency"] = key;
            record["Bid Rate"] = value;
            record["Ask Rate"] = value;
            if (valids.indexOf(record["Currency"]) > 0) {
              this.dataset.push(record);
            }
          });
    
          if (this.dataset.length > 0) {
            this.$refs.pivot.flexmonster.updateData(
              {
                data: this.dataset,
              },
              {
                partial: true,
              }
            );
          }
        },
        randomFloatBetween(minValue, maxValue, precision) {
          if (typeof precision === "undefined") {
            precision = 4;
          }
    
          return parseFloat(
            Math.min(
              minValue + Math.random() * (maxValue - minValue),
              maxValue
            ).toFixed(precision)
          );
        },
        updateData() {
          let numbers = [];
    
          for (let i = 0; i < this.dataset.length; i++) {
            // Generate an array of numbers that are used for indices
            numbers[i] = i;
          }
    
          const shuffleArray = (arr) => arr
            .map((a) => [Math.random(), a])
            .sort((a, b) => a[0] - b[0])
            .map((a) => a[1]);
    
          let random_permutation = shuffleArray(numbers);
          random_permutation.forEach((index) => {
            let item = this.dataset[index];
            let prev_rate;
            let new_rate;
    
            if (index % 2 === 0) {
              prev_rate = item["Bid Rate"];
              new_rate = prev_rate + this.randomFloatBetween(0.01, 0.3, 3);
              item["Bid Rate"] = new_rate;
              item["Ask Rate"] = new_rate - this.randomFloatBetween(0.01, 0.3, 3);
              this.dataset[index] = item;
            } else {
              prev_rate = item["Bid Rate"];
              new_rate = prev_rate - this.randomFloatBetween(0.01, 0.2, 3);
              if (new_rate > 0) {
                item["Bid Rate"] = new_rate;
                item["Ask Rate"] = new_rate + this.randomFloatBetween(0.01, 0.2, 3);
                this.dataset[index] = item;
              } else {
                new_rate = prev_rate + this.randomFloatBetween(0.01, 0.2, 3);
                item["Bid Rate"] = new_rate;
                item["Ask Rate"] = new_rate - this.randomFloatBetween(0.01, 0.2, 3);
                this.dataset[index] = item;
              }
            }
          });
          this.$refs.pivot.flexmonster.updateData(
            {
              data: this.dataset,
            },
            {
              partial: true,
            }
          );
        },
        customizeCell(cell, data) {
          if (data.hierarchy?.uniqueName === "Currency" && data.member) {
            cell.addClass("header-cell");
            let names = data.member.caption.split("/");
            let flag = `<img class="flag" style="width:36px; height:24px;"
              src="https://cdn.flexmonster.com/flags/${names[0].toLowerCase()}.svg">`;
            cell.text = `<div style="display:flex; align-items:center; font-size:12px;
              position:relative; bottom: 4px;">${flag} ${names[0]}</div>`;
          }
        },
        onReportComplete() {
          this.$refs.pivot.flexmonster.off("reportcomplete");
          this.getData();
          this.updateData();
          setInterval(() => {
            this.updateData();
          }, 6000);
        },
      },
    };
    </script>
    
    .header-cell {
      background-color: #F7F7F7 !important;
      border-bottom: 1px solid #E9E9E9 !important;
      border-right: 1px solid #E9E9E9 !important;
    }
    
    #fm-pivot-view .fm-grid-layout div.fm-cell {
      padding-left: 20px;
    }
    
    #fm-pivot-view .fm-header {
      background-color: #e9e9e9 !important;
      border-right: 1px solid #d5d5d5 !important;
      border-bottom: 1px solid #d5d5d5 !important;
    }
    
    .fm-updated-cell-down {
      color: #DF3800 !important;
      font-weight: bold !important;
      background-image: none !important;
      -webkit-animation: fadeIt 5s ease-in-out;
      -moz-animation: fadeIt 5s ease-in-out;
      -o-animation: fadeIt 5s ease-in-out;
      animation: fadeIt 5s ease-in-out;
    }
    
    .fm-updated-cell-down::before {
      content: "\2193 \00a0";
      position: relative;
      bottom: 2px;
    }
    
    .fm-updated-cell-up {
      color: #00A45A !important;
      font-weight: bold !important;
      background-image: none !important;
      -webkit-animation: fadeIt1 5s ease-in-out;
      -moz-animation: fadeIt1 5s ease-in-out;
      -o-animation: fadeIt1 5s ease-in-out;
      animation: fadeIt1 5s ease-in-out;
    }
    
    .fm-updated-cell-up::before {
      content: '\2191 \00a0';
      position: relative;
      bottom: 2px;
    }
    
    @-webkit-keyframes fadeIt {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      50% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @-moz-keyframes fadeIt {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      50% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @-o-keyframes fadeIt {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      50% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @keyframes fadeIt {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      50% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @-webkit-keyframes fadeIt1 {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      50% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @-moz-keyframes fadeIt1 {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      50% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @-o-keyframes fadeIt1 {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      50% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @keyframes fadeIt1 {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      50% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    

    In this demo, you can see the live streaming updates of JSON data. With the conditional formatting, we highlighted changes in values.

    Using updateData() function you can update the data without in your slice and formatting. With this approach, we increased the data loading speed as there is no need to reload the report.