What is the best way to update data in Highcharts with Vue 3?

Issue with Updating Highcharts Data Using Vue.js 3

Within my Vue.js 3 web application, I have integrated a Highcharts Chart alongside some statistics display. This setup includes global buttons for time-filtering options such as All, Year, Month, and Week. The challenge I am facing is ensuring that the data in my Highchart chart updates dynamically whenever one of these time-filter buttons is pressed.

To achieve this functionality, I have utilized a Vue3 wrapper for Highcharts, which can be found on GitHub: Wrappers Github

While the initial data display works perfectly, the process of updating the data is notably sluggish. This sluggishness has led me to believe that there may be an error in how I am handling the data update process.

To further illustrate my issue, I have uploaded a video demonstration on YouTube: https://youtu.be/GEjHqoAElgI

Furthermore, I have created a minimal reproducible example on CodeSandbox: https://codesandbox.io/s/blissful-goldwasser-zq8je?fontsize=14&hidenavigation=1&theme=dark

Within this example, there is a Chart.vue component that updates its "data" property when the "Update Data" button is pressed. Despite the ability to toggle the button multiple times, there is a delay of several seconds before the chart updates.

I have experimented with passing the data to my Chart component as a property and utilizing a watcher to trigger chart updates when the data changes. While this method technically works, the chart updating process remains slow (3-5 seconds).

Below is the code snippet for my component:

<template>
  <VueHighcharts
    class="hc"
    :options="options"
    :deepCopyOnUpdate="true"
    :redrawOnUpdate="true"
    :oneToOneUpdate="false"
    :animateOnUpdate="false"
  />
</template>

<script>
import VueHighcharts from "vue3-highcharts";

export default {
  name: "CoinChart",
  components: {
    VueHighcharts,
  },
  props: {
    stats: [Object],
  },
  data() {
    return {
      options: {
        title: {
          text: "Coins",
        },
        series: [
          {
            name: "ETH",
            data: [],
          },
          {
            name: "BTC",
            data: [],
          },
        ],
      },
    };
  },
  watch: {
    stats: {
      immediate: true, // Despite comments, this line does play a role
      handler: function (val) {
        const eth = new Array();
        const btc = new Array();
        this.options.series[0].data = [];
        this.options.series[1].data = [];

        for (let i in val) {
          eth.push([val[i].time * 1000, val[i].coinsPerHour]);
          btc.push([val[i].time * 1000, val[i].btcPerHour]);
        }

        this.options.series[0].data = eth;
        this.options.series[1].data = btc;
      },
    },
  },
};
</script>

This challenge has consumed a significant amount of my time – 4 hours today alone – without yielding any success. I have even considered switching to Chart.js, but it appears that Chart.js lacks robust compatibility with Vue.js 3 as well.

Answer №1

I finally figured it out.

It appears that Highcharts updates by assigning new values to the existing series in order to calculate animations. This process can be quite heavy, causing a delay of 2-3 seconds, as you have noticed.

A more efficient approach is to simply discard the current chart (using a v-if) and generate a new one with the updated dataset:

<template>
  <VueHighcharts v-if="showChart" :options="options" />
</template>
import VueHighcharts from "vue3-highcharts"

export default {
  name: 'Chart',
  components: {
    VueHighcharts
  },
  props: {
    series: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      showChart: true
    }
  },
  computed: {
    options() {
      return {
        //...
        series: this.series
      }
    }
  },
  watch: {
    series: {
      handler() {
        // destroy the current chart
        this.showChart = false
        this.$nextTick(() => {
          // render a new chart with updated data
          this.showChart = true
        })
      }
    }
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Instructions for relocating the ending of a javascript range to a sentence within the Chrome browser

When working with a javascript range object, Internet Explorer offers a moveEnd method that can shift the end of a range by a specified number of sentence units. How can a similar functionality be achieved in Chrome? Below is the code I have written that ...

Is it possible for JavaScript to create an object that, when accessed directly, will return a string or number, and when its property is accessed, it will return that

something like this: const object = { value: 'value', label: 'label' } object === 'value' // true, accessing it directly returns 'value' object.label === 'label' // true object.value === 'value&ap ...

Exploring Nextjs with server-side rendering and fetching data from

When utilizing the getServerSideProps function in Next.js to make a fetch request to my API, I encountered an issue where the origin header was coming back as undefined. This seems to be specific to requests made from the server in Next.js, as I am able ...

Transforming the input button into images

I'm new to JavaScript and I'm looking to change the show button and hide button to images instead. The show button image should be different from the hide button image. Can anyone guide me on how to achieve this? Click here for reference $( ...

Server vs Client-Side: Loading Dynamic HTML

Currently, I am working on a project that involves making AJAX calls to load hundreds of records from the database to be displayed on a slider. Specifically, the data I am retrieving includes the 'Image Path' for all the images, as well as other ...

Display every div element if none of the links have been clicked

On my webpage at url.com/yourfirstpage/, all div elements are hidden by default with a display:none property. If we specifically target #sec1 by going to url.com/yourfirstpage/#sec1, only sec1 is displayed while the others remain hidden. But what if we acc ...

Angular JS: Saving information with a promise

One dilemma I am facing is figuring out where to store data that needs to be accessed in the final callbacks for an http request. In jQuery, I could easily handle this by doing the following: var token = $.get('/some-url', {}, someCallback); tok ...

Preventing the keyboard from showing on mobile devices when using a React date time picker

I am currently utilizing the React-date-picker component in my ReactJS application. I am encountering an issue where the keyboard is appearing along with the date picker when testing on mobile devices. I have attempted some solutions, but none have resol ...

The perplexing behavior of RxJS Observables with Mongo Cursors

Recently, I've been working on converting a mongo cursor into an observable using my own RxJS implementation. Despite finding numerous solutions online, I wanted to challenge myself by creating one from scratch. I would greatly appreciate it if someo ...

Updating nested forms in Angular 4

The nested form structure I am working with is a 'triple level' setup: FormGroup->ArrayOfFormGroups->FormGroup At the top level (myForm): this.fb.group({ name: '', description: '', q ...

What is the best way to retrieve all string constants from HTML or JSX code?

UPDATE: I recently developed my own babel plugin CLI tool named i18nize-react :D I am currently in the process of translating an existing react application from English to another language. The string constants in the JSX are all hardcoded. Is there a sim ...

The Angular Factory service is accurately retrieving data, but unfortunately, it is not being displayed on the user interface

Here is a link to the complete source code angular .module('app') .factory('Friends', ['$http',function($http){ return { get: function(){ return $http.get('api/friends.json') .t ...

Unique column arrangement specifically designed for the initial row within the loop

My webpage features a layout that showcases 4 images on each row. However, I am looking to create a special first row with a unique column configuration compared to the rest of the rows. Here is an example of what I have in mind: https://i.sstatic.net/Rs ...

Implementing an active class in Vue.js for the router-link component

I am facing an issue with my sidebar item becoming inactive when I click on a sublink inside a component. How can I prevent the active class from switching off? Here is my sidebar: <router-link to='/sub/success_tools_subscriptions' ...

What are the steps to execute a module designed for NodeJS v6 LTS ES2015 in Meteor 1.4.x?

While I understand that Meteor includes NodeJS as a dependency, I'm facing an issue with a module written in ES6 that has a default argument value set within one of the Class methods. The problem arises when using Meteor v1.4.3.2: (STDERR) packages/m ...

Modifying the design of a website in real-time using the EXPRESS.js and NODE.js frameworks

I successfully set up a simple website using node.js and express.js by following this helpful tutorial. My express implementation is structured like this with a jade file for the web interface. // app.js var express = require('express'), r ...

Employing jQuery to extract the text from the h4 class="ng-binding" element beyond the Angular scope

Is it possible to retrieve the current text content of <h4 class="ng-binding"></h4>? The text content is generated dynamically within the angular.js setup. I am interested in finding a way to extract this text using jQuery or JavaScript from ...

Error: Unable to locate npm package

I am currently working on an Angular application that was created using Grunt and relies on Bower and NPM. Recently, I attempted to install an npm module locally. The installation resulted in the files being stored in the main application directory under ...

How to access an element from the JSON return value retrieved from an AJAX call using JavaScript

After making an ajax call that returns successfully, I am facing a problem. I cannot access individual elements of the array it returns, and therefore unable to console log it. The error message indicates that the track is not defined, even though it is pr ...

Tips for utilizing v-bind to bind to an object-type prop

After checking out this informative link, I am attempting to implement the example demonstrated in the section titled Binding Multiple Properties Using an Object. Within the parent component, I have the following object: const post = { id: 1, title: & ...