Update Chart vue3-chart with new data - javascript

I have Chart.js Chart in a Vue component using vue3-chart-v2.
Everything works fine untill I want to update the data.
Right now, I am using a watcher to check if the data changes.
This works, but updating the chart does not.
My idea was to destroy the chart when the data has changed and rerender it with the new data
I have seen some questions on stack using the mixins reactiveData/ reactiveProp but somehow I can not acces them using vue3-chart-v2, I only get an error.
Could someone help me out?
This my first question here on stack
My code:
<script>
import { defineComponent } from 'vue';
import { Doughnut } from 'vue3-chart-v2';
export default defineComponent({
name: 'PieChart',
extends: Doughnut,
props: {
carbonData: Object
},
data() {
return {
chartData: {
labels: ['Slabs', 'Columns', 'Foundation', 'Core'],
datasets: [
{
data: [ this.carbonData.slabs, this.carbonData.columns, this.carbonData.foundation, this.carbonData.core ],
backgroundColor: ['#8FBC8F', '#87CEFA', '#CD853F', '#e64e3e'],
borderWidth: 1,
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
legend: {
position: 'right',
}
}
}
},
mounted () {
this.renderPieChart();
},
methods: {
renderPieChart() {
this.renderChart(this.chartData, this.options);
}
},
watch: {
carbonData : {
deep: true,
handler() {
this.state.chartObj.destroy();
this.renderChart(this.chartData, this.chartOptions);
},
}
},
})
</script>

We use a simple method:
add a v-if to your chart, for example v-if="renderChart"
It is false in the beginning but when data is loaded change it to true
Whenever you expect the data to change, change it to false again and after change of data update it to true once again.
It has worked for us for a long time now.

Related

Cannot access variables in angular from d3 Funnel js callback

As per the latest document in D3 JS funnel I have click event callback as referred by the documentation. But when I'm unable to access functions from inside angular component using this.try().
Here is the implementation, don't know how to implement it.
JS Code
const options = {
chart: { bottomPinch: 1, animate: 200, height: 300 },
block: {
// dynamicHeight: true,
// dynamicSlope: true,
highlight: true,
},
events: {
click: {
block(d) {
console.log(d.label.raw);
this.try(d.label.raw);
},
},
},
tooltip: { enabled: true, }
};
const chart = new D3Funnel('#d3Funnel');
chart.draw(data, options);
})
HTML
<div id="d3Funnel"></div>
It gives the error
ERROR TypeError: this.try is not a function
at SVGPathElement.block
I don't know how to resolve this.
Reference of library
https://github.com/jakezatecky/d3-funnel
block(d) { ... } is just a shorthand for block: function(d) { ... }, which would not lexically bind this.
If you replaced your event with an arrow function, such as block: (d) => { ... }, your code would be able to resolve this as you intend.

Using data from API with Chart JS

I am getting data from an api and then reformatting part of it into an array using .map(), I am successfully able to do this, but when it comes time to pass it into Chart JS as data it does work. I am able to pass in a normal, hard coded, array but not my own data...
I tried using an Angular directive (NG2-Charts) to help out thinking maybe that was the problem, but that doesn't work either...
Component.ts:
... Other variable and stuff up here...
getStockData() {
this.stocksService.getStockData()
.subscribe(
(response) => {
for(var i = 0; i < response.length; i++) {
this.stockOpen.push(response[i]['open']);
}
console.log('after loop: ', this.stockOpen);
},
(error) => console.error(error)
);
console.log('real: ', this.stockOpen);
console.log('test: ', this.testData);
}
// Chart JS version
buildStockChart() {
var ctx = document.querySelector("#chart");
this.chart = new Chart(ctx, {
type: 'bar',
data: {
labels: [1,2,3,4,5],
datasets: [
{
data: this.stockOpen,
borderColor: "#3cba9f",
fill: false
}
]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
display: true
}],
yAxes: [{
display: true
}],
}
}
});
}
// NG2-Charts version
public lineChartData:Array<any> = [
{data: this.testData},
];
public lineChartLabels:Array<any> = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
public lineChartOptions:any = {
responsive: true
};
Result from console.log():
i also have same problem with chart JS on angular so i force to use another chart.
im now using angular 2 chart js.
i think the problem here is the delay of data fetch by API, the CHART component is already render on html view but the data is still not fetch by the API service.
try to add this code on your code block. This will handle the data if API service data is available.
()=>{this.buildStockChart();}
this.stocksService.getStockData()
.subscribe(
(response) => {
for(var i = 0; i < response.length; i++) {
this.stockOpen.push(response[i]['open']);
}
console.log('after loop: ', this.stockOpen);
},
()=>{
this.buildStockChart();
}
);
console.log('real: ', this.stockOpen);
console.log('test: ', this.testData);
}
This chart is easy to manage for dynamic instances.
Hope this chart will work on you.
https://www.npmjs.com/package/angular2-chartjs
When are you calling the buildStockChart() method?
You should call it right after the for loop into the callback you pass to the subscribe method, since that's the moment when this.stockOpen is populated (before that moment it will be empty as you are seeing in the console).
As #Joseph Agbing, I was unable to get it work with angular 7. I'm now using chart.js only
npm install chart.js --save
with into my someChart.component.html
<div style="display: block"><!--Mandatory div including chart-->
<canvas id="canvas">{{chart}}</canvas>
</div>
into my someChart.component.ts
called from my httpClient.post(...).subscribe(lData => (setChartDataFromEntities(lDataProcessed), ...)
import { Chart } from 'chart.js';
export class someClass {
/**
*
* #param aDate
* #param aChargeUnitArray
*/
setChartDataFromEntities( aDate: Date, aChargeUnitArray: ChargeUnit[] ){
console.debug('setChartDataFromEntities->', aChargeUnitArray)
let lChartDataArray = []
let lChartDataLineDataArray: Array<Number> = []
let lChartLabelsArray: string[] = []
let l_s: string
aChargeUnitArray.forEach(element => {
lChartDataLineDataArray.push(element.charge)
lChartLabelsArray.push(MiscHelper.dateTimeHMSForChart(element.timestamp))
});
lChartDataArray.push(
{
data: lChartDataLineDataArray,
label: MiscHelper.dateForGui(aDate),
}
)
this.chart = new Chart('canvas', {
type: 'line',
data: {
labels: lChartLabelsArray,
datasets: lChartDataArray
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
display: true
}],
yAxes: [{
display: true
}],
}
}
});
this.statusMessage = 'Chart loaded'
}
hope it helps somebody more than the day I wasted trying to get it work...

Polymer one-way-binding not working

After hours of trying I'm clueless. Maybe some of you have the answer. I've create a Polymer template like this:
<dom>
</dom>
<script>
Polymer ({
is: 'foo',
proprties: {
timeRange: {
type: String,
value: 'day',
readOnly: true,
observer: "_refresh",
},
...
},
...
});
</script>
The observer function is just for debugging. The calling host uses this like that:
<dom>
<foo time-range='[[timeRange]]'></foo>
</dom>
<script>
Polymer ({
is: 'host',
proprties: {
timeRange: {
type: String,
value: 'day',
readOnly: true,
notify: true,
observer: "timeRangeChanged",
},
...
},
onDayTap: function() {
this._setTimeRange('day');
},
onMonthTap: function() {
this._setTimeRange('month');
},
onYearTap: function() {
this._setTimeRange('year');
},
...
});
</script>
The 'timeRangeChanged' observer refreshes a chart. But the timeRange-property in foo never gets changed - the _refresh-observer gets called only once on start. What am I doing wrong.
Hope somebody can help me out here
PS. I'm using Polymer 1.0
Hope this will help:
https://jsfiddle.net/fLbp26kp/
Polymer ({
is: 'foo',
properties: {
timeRange: {
type: String,
value: 'day'
observer: "_refresh",
}
}
});
If you're trying to update foo.timeRange you would need to remove readOnly from timeRange in order for it to be set from somewhere else.
Foo without readOnly.

Highlight Single Bar/Column in Highcharts on load

I have an existing highchart on which I need to highlight a single column.
It is a percentile graph that has been around for a while, I am still pretty new to high charts, but I have seen a similar question here on SO, this question, though deals with stacked bars and a click event...
The code makes sense to me in the example, but I guess I am missing something,
Here is my sample (trying to highlight the 24th column)
https://jsfiddle.net/52t43y3k/2/
Here is the question I saw:
Highlight one bar in a series in highcharts?
for ref, my code is
var col_chart = $('#section-2-chart').highcharts({
chart: {
type: 'column'
},
tooltip: { enabled: false },
credits:false,
title: false,
xAxis: {
title:{text:'PERCENTILES'},
type: 'Percentile',
labels: {
enabled:true,
formatter: function() {
return this.value*2;
}
}
},
yAxis: {
min: 0,
title:{text:'Total Image Weight'}
},
legend: {
enabled: false
},
series: [{
data: [169,12003,38308.5,61739.7,97069,131895.5,161086.7,198758.7,219779.3,243567.7,276607.7,296931.5,327457.5,362840.3,383978,410685.5,443774,467039.5,491654,517205,544754.7,578468.3,605392.5,644214.5,693765,766953.7,806616,855380.7,894161,942282,1001179.7,1062697.7,1125773.3,1186437,1236893.7,1314379.5,1378944,1454090.3,1553065,1689346,1833150,1957396,2077851.5,2228644.7,2390102,2725365.5,3147844.3,3607372,4239281.5,5190061,9422370.8],
tooltip: {
pointFormat: '<b>{point.y:f} Bytes</b>'
}
}]
});
//TRIED THIS AND series.data[24] - essentially the 24th bar should be highlighted
col_chart.series[0].data[24].update({color:'red'});
You need to access the highcharts off of your jquery object:
col_chart.highcharts().series[0].data[24].update({
color: 'red'
});
For clarity
In your example, the following is true:
console.log(col_chart instanceof jQuery); // true
From the highcharts source:
/**
* Register Highcharts as a plugin in jQuery
*/
if (win.jQuery) {
win.jQuery.fn.highcharts = function () {
var args = [].slice.call(arguments);
if (this[0]) { // this[0] is the renderTo div
// Create the chart
if (args[0]) {
new Highcharts[ // eslint-disable-line no-new
isString(args[0]) ? args.shift() : 'Chart' // Constructor defaults to Chart
](this[0], args[0], args[1]);
return this;
}
// When called without parameters or with the return argument, return an existing chart
return charts[attr(this[0], 'data-highcharts-chart')];
}
};
}
Meaning, highcharts() is a plugin for jQuery, so you can access it (assuming it's been attached to the dom element already, as in your case above) by calling highcharts off a jQuery selector instance.

Adding data to highcharts(Highstock) when user scrolling reaches left end

I'm using highstock on my website. The scroll bar in the navigator of stock chart is drawn using SVG. I want to add more data(via ajax) to the graph when user scrolls to the leftmost end.
I am new to SVG and not sure how to detect that user has scrolled to the end and fire a ajax query based on that. Can anyone help me with this.
Thanks,
Sivakumar.
So, today I had the same problem, and I just found your question.
I don't know if you have any reason for loading the new data only when the user moves the scrollbar, I would recommend to fire the ajax query if the user visualizes the left-most data, instead (that is: scrolling the bar, pressing the left arrow, dragging the area of the navigation chart, and so on).
If this solution applies to you, you can try with something like this:
chart = new Highcharts.StockChart({
chart: {
renderTo: 'chart',
events: {
redraw: function(event) {
if (chart.xAxis) {
var extremes = chart.xAxis[0].getExtremes();
if (extremes && extremes.min == extremes.dataMin) {
console.log("time to load more data!");
}
}
}
}
}, [...]
I solved this problem in the following way.
<script>
import axios from 'axios';
export default {
name: 'Chart',
data() {
return {
chartOptions: {
chart: {
events: {
// we will lose the context of the component if we define a function here
}
},
series: [{
type: 'candlestick',
data: null,
}],
},
};
},
methods: {
onRedraw: function () {
let chart = this.$refs.chart.chart
if (chart.xAxis) {
let extremes = chart.xAxis[0].getExtremes()
console.log(extremes)
if (extremes && extremes.min <= extremes.dataMin) {
console.log("time to load more data!");
}
}
}
},
created() {
axios.get('https://demo-live-data.highcharts.com/aapl-ohlcv.json').then((response) => {
this.chartOptions.series[0].data = response.data
this.chartOptions.series[0].name = 'AAPL'
});
this.chartOptions.chart.events.redraw = this.onRedraw
},
};
</script>
<template>
<highcharts :constructor-type="'stockChart'" :options="chartOptions" ref="chart"></highcharts>
</template>

Categories

Resources