Image with dynamic data vuejs and chart.js - javascript

I have this code to show bar-chart with VueJS:
Vue.component('bar-chart', {
extends: VueChartJs.Bar,
data: function () {
return {
datacollection: {
labels: ['MICROFINANZAS -SECTOR COMERCIO','MICROFINANZAS -SECTOR SERVICIOS'],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
pointBackgroundColor: 'white',
borderWidth: 1,
pointBorderColor: '#249EBF',
data: [15000, 71700]
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
},
gridLines: {
display: true
}
}],
xAxes: [{
ticks: {
beginAtZero: true
},
gridLines: {
display: false
}
}]
},
legend: {
display: false
},
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
label: function (tooltipItems, data) {
return '$' + tooltipItems.yLabel;
}
}
},
responsive: true,
maintainAspectRatio: false,
height: 200
}
}
},
mounted() {
// this.chartData is created in the mixin
this.renderChart(this.datacollection, this.options)
}
})
Method in VueJS
var app = new Vue({
el: '#grid',
data: {
columns: ['id', 'nombre'],
objeto: "",
searchQuery: "",
dataChart: "",
dataChart1: "",
},
created: function () {
this.getDeudas();
},
methods: {
getDeudas: function () {
this.$http.get(baseURL + "/Home/ConsultarDeudasHome").then(function (response) {
this.lista = response.data.data;
console.log(this.lista);
this.objeto = JSON.parse(this.lista);
console.log(this.objeto[1].original);
this.dataChart = [this.objeto[0].original, this.objeto[0].actual];
console.log(this.dataChart);
this.dataChart1 = [this.objeto[1].original, this.objeto[1].actual];
});
},
},
This code show this bar chart:
But I need replace in my code two variables dynamic:
labels: ['MICROFINANZAS -SECTOR COMERCIO','MICROFINANZAS -SECTOR SERVICIOS'],
data: [15000, 71700]
With the information of method getDeudas()
How can to made this action?

This is the solution, I use props and watch:
Vue.use(VueTables.ClientTable);
Vue.component("bar-chart", {
extends: VueChartJs.Bar,
props: ["data", "options"],
mounted() {
this.renderLineChart();
},
computed: {
chartData: function () {
return this.data;
}
},
methods: {
renderLineChart: function () {
this.renderChart(
{
labels: ["Sector Comercio", "Sector Servicios"],
datasets: [
{
label: "Consolidado",
backgroundColor: "#f87979",
data: this.chartData
},
],
},
{ responsive: true, maintainAspectRatio: false }
);
}
},
watch: {
data: function () {
this.renderLineChart();
}
}
});
const baseURL = window.location.protocol + "//" + window.location.host;
var app = new Vue({
el: '#grid',
data: {
columns: ['id', 'nombre'],
objeto: "",
dataChart: "",
},
created: function () {
this.getDeudas();
},
methods: {
getDeudas: function () {
this.$http.get(baseURL + "/Home/ConsultarDeudasHome").then(function (response) {
this.lista = response.data.data;
this.objeto = JSON.parse(this.lista);
this.dataChart = [this.objeto[0].original, this.objeto[1].original];
});
},
},
})

Related

How to Re-Initiate the child component in vueJs 3?

I need to change the values and re-initiate the component with props Data.
i tried with $emit unfortunately doesn't work my code.
chart.vue
<template>
<div class="col-12">
<div class="card">
<div class="card-header header-elements">
<div>
<h5 class="card-title mb-0">Statistics</h5>
</div>
<div class="card-header-elements ms-auto py-0">
<select name="status" class="form-select form-select-sm" v-model="chartType" #click="$emit('someEvent')">
<option value="daily" data-label="Days">Last 7 Days</option>
<option value="weekly" data-label="Weeks">Weekly</option>
<option value="monthly" data-label="Months">Monthly</option>
</select>
</div>
</div>
<div class="card-body">
<line-chart v-bind:chartData="chartData" v-bind:chartOptions="chartOptions" v-if="showLineGraph" #some-event="chartData"></line-chart>
</div>
</div>
</div>
</template>
<script>
export default {
props: {},
mounted() {
},
created(){
this.params.params = {
chart_type: "daily",
};
this.chartOptions.scales.xAxes[0].scaleLabel.display = "DAYS";
this.chartOptions.scales.xAxes[0].scaleLabel.labelString = "DAYS";
this.loadGraph();
},
data() {
return {
chartType:'daily',
showLineGraph:false,
params: {
params: {}
},
datasetSample: {
data: [],
label: "",
borderColor: "#ff5b5c",
tension: 0.5,
pointStyle: "circle",
backgroundColor: "#ff5b5c",
fill: false,
pointRadius: 1,
pointHoverRadius: 5,
pointHoverBorderWidth: 5,
pointBorderColor: "transparent",
pointHoverBorderColor: "#fff",
pointHoverBackgroundColor: "#ff5b5c",
height: 500
},
chartData: {
labels: [],
datasets: []
},
chartOptions: {
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [{
scaleLabel: {
display: "",
labelString: ""
},
gridLines: {
display: true,
},
}],
yAxes: [{
beginAtZero: true,
scaleLabel: {
display: "Amount In INR",
labelString: "Amount In INR"
},
gridLines: {
display: true,
},
ticks: {
maxTicksLimit: 10,
beginAtZero: false,
callback: function (value, index, values) {
return value.toLocaleString();
}
}
}]
},
legend: {
position: 'top',
align: 'start',
labels: {
usePointStyle: true,
padding: 15,
boxWidth: 6,
boxHeight: 6,
}
},
plugins: {
tooltip: {
// Updated default tooltip UI
backgroundColor: "#fff",
titleColor: "#000",
bodyColor: "#000",
borderWidth: 1,
borderColor: "#0560e8"
}
}
}
};
},
methods: {
loadGraph: function () {
this.chartData.datasets=[];
this.chartData.labels = [];
axios.get(window.location.href + "/get-chart-data", this.params)
.then(response => {
console.log(response.data);
if (response.data.status == 200) {
let datasets = response.data.data.datasets;
let chart_vlaues=[];
for (var key in datasets) {
if (datasets.hasOwnProperty(key)){
let temp_dataset = Object.assign({}, this.datasetSample);
temp_dataset.data = datasets[key].values;
temp_dataset.label = key;
temp_dataset.borderColor = datasets[key].colour;
temp_dataset.backgroundColor = datasets[key].colour;
temp_dataset.pointHoverBackgroundColor = datasets[key].colour;
chart_vlaues.push(temp_dataset);
}
}
this.chartData.datasets=chart_vlaues;
this.chartData.labels = response.data.data.labels;
this.showLineGraph=true;
}else {
this.chartData.datasets = [];
this.chartData.labels = [];
this.showLineGraph = true;
}
})
.catch(err => {
console.log(err);
console.log("Chart could not loaded.");
})
.then(() => {
});
},
}
}
</script>
LineChart.Vue
<script>
import { defineComponent } from 'vue'
import { Chart as ChartJS, Title, Tooltip, Legend,Line} from 'vue3-chart-v2'
export default defineComponent({
name: 'LineChart',
extends: Line,Tooltip,Legend,Title,
props: {
chartData: {
type: Object,
required: true
},
chartOptions: {
type: Object,
required: false
},
},
watch : {
someEvent: function (value) {
console.log('from watch');
}
},
mounted () {},
created(){
this.renderChart(this.chartData, this.chartOptions);
},
data(){
},
methods:{
someEvent:function(){
alert('iiiiiiiiii');
}
},
emits: {
someEvent(payload) {
console.log('some emits');
}
}
})
</script>
app.js
require('./bootstrap')
import { createApp } from 'vue'
import lineChart from './components/lineChart';
import chart from './components/chart.vue';
const app = createApp({})
app.component('chart', chart);
app.component('line-chart', lineChart);
app.mount('#app')
You use watchers wrong. They are not for watching events.
watch : {
someEvent: function (value) {
console.log('from watch');
}
},
You also did not define your custom event with emits
Please, check the Vue docs about the Component Events
The typical data flow with Vue components is
to the Component: App -> Data -> Component Props -> Watchers -> Methods
from The component: Data -> Event -> Event Handler -> App
So, if you want to re-initiate your child component, that you should update some child component's prop and then react to the change in some child component's watcher.

I'm getting an error when drawing a chart using echarts JS

When I try to draw a graph, I get an error:echarts.min.js:45 Uncaught TypeError: Bind must be called on a function at bind (<anonymous>) at Bd (echarts.min.js:45:130031)
My echarts-init.js:
let domTemp = document.getElementById("main");
let mytempChart = echarts.init(domTemp, null, {
renderer: 'canvas',
useDirtyRect: false
});
var app = {};
var option;
runDaysDatas(sens_data_result, sens_name_list);
function runDaysDatas(sens_data_result, sens_name_list) {
const sens_names = sens_name_list;
const datasetWithFilters = [];
const seriesList = [];
echarts.util.each(sens_names, function (sens) {
var datasetId = 'dataset_' + sens;
datasetWithFilters.push({
id: datasetId,
fromDatasetId: sens_data_result,
transform: {
type: 'filter',
config: {
and: [
{ dimension: 'Uid', '=': sens }
]
}
}
});
seriesList.push({
type: 'line',
datasetId: datasetId,
showSymbol: false,
name: sens,
endLabel: {
show: true,
formatter: function (params) {
return params.value[3] + ': ' + params.value[0];
}
},
labelLayout: {
moveOverlap: 'shiftY'
},
emphasis: {
focus: 'series'
},
encode: {
x: 'Date',
y: 'Temperature',
label: ['Name', 'Temperature'],
itemName: 'Date',
tooltip: ['Temperature']
}
});
});
option = {
animationDuration: 10000,
dataset: [
{
id: 'dataset_sens_names',
source: sens_data_result
},
...datasetWithFilters
],
title: {
text: 'Temperature for Day'
},
tooltip: {
order: 'valueDesc',
trigger: 'axis'
},
xAxis: {
type: 'category',
nameLocation: 'middle'
},
yAxis: {
name: 'Temperature'
},
grid: {
right: 140
},
series: seriesList
};
mytempChart.setOption(option);
}
In sens_data_result i pass data from api.
In sens_name_list i pass names of the sensors.
The console does not send errors to my script, it swears at the library. I took an example from the official site and remade it for my task, displaying the temperature by time of day with the name of the sensor. There can be N number of graphs on one chart.
Thnx for help!
Okey, i'm a solved the problem, this is decision:
let url = '/api/sensdata';
let domTemp = document.getElementById("main");
let mytempChart = echarts.init(domTemp, null, {
renderer: 'canvas',
useDirtyRect: false
});
var app = {};
var option;
$.get(
url,
sensors_uid,
(_rawData) => {
runDaysDatas(_rawData, sens_name_list);
}
);
function runDaysDatas(_rawData, sens_names) {
const datasetWithFilters = [];
const seriesList = [];
_rawData.unshift(['Name', 'Date', 'Humidity', 'Temperature']);
echarts.util.each(sens_names, function (sens) {
var datasetId = 'dataset_' + sens;
datasetWithFilters.push({
id: datasetId,
fromDatasetId: 'dataset_raw',
transform: {
type: 'filter',
config: {
and: [
{ dimension: 'Name', '=': sens }
]
}
}
});
seriesList.push({
type: 'line',
datasetId: datasetId,
showSymbol: false,
name: sens,
endLabel: {
show: true,
formatter: function (params) {
return 'Uid ' + params.value[0] + ': ' + params.value[3] + '°C';
}
},
labelLayout: {
moveOverlap: 'shiftY'
},
emphasis: {
focus: 'series'
},
encode: {
x: 'Date',
y: 'Temperature',
label: ['Name', 'Temperature'],
itemName: 'Temperature',
tooltip: ['Temperature']
},
});
});
console.log(seriesList);
option = {
toolbox: {
show : true,
feature : {
magicType : {show: true, type: ['line', 'bar']},
restore : {show: true},
saveAsImage : {show: true}
}
},
legend: {},
dataset: [
{
id: 'dataset_raw',
source: _rawData
},
...datasetWithFilters
],
tooltip: {
order: 'valueDesc',
trigger: 'axis'
},
xAxis: {
type: 'time',
nameLocation: 'middle',
axisLabel: {
formatter: (function(value){
moment.locales('RU_ru');
return moment(value).format('MM/DD HH:mm');
})
}
},
yAxis: [
{
type : 'value',
axisLabel : {
formatter: '{value} °C'
}
}
],
grid: {
right: 140
},
series: seriesList
};
mytempChart.clear();
mytempChart.setOption(option);
}
window.addEventListener('resize', mytempChart.resize);

How to Render Chart Datasets in Vue?

I am currently making a reports page and currently struggling how to render the dataset to my BarChart. I have no problems showing static data to the chart but when I use axios it does not work. I read solutions about using watchers and mounted. But I am confused how to apply it if my BarChart is in another component.
This is my BarChart Code:
import { Bar } from "vue-chartjs";
export default {
name: "BarChart",
extends: Bar,
data() {
return {};
},
props: {
label: {
type: Array,
},
chartData: {
type: Array,
},
options: {
type: Object,
},
},
mounted() {
const dates = this.chartData.map((d) => d.date);
const totalCheckIn = this.chartData.map((d) => d.totalCheckIn);
const totalCheckOut = this.chartData.map((d) => d.totalCheckout);
this.renderChart(
{
labels: dates,
datasets: [
{
label: this.label[0],
data: totalCheckIn,
},
{
label: this.label[1],
data: totalCheckOut,
},
],
},
this.options
);
},
};
In my reports component this is how I used it:
<BarChart
v-bind:chartData="checkIn"
v-bind:options="checkInOptions"
v-bind:label="checkInLabel"
></BarChart>
import BarChart from "../components/BarChart";
export default {
name: "Reports",
components: { BarChart },
data() {
return {
checkInOptions: {
responsive: true,
maintainAspectRatio: false,
},
checkIn: [
{ date: "1", totalCheckIn: "2", totalCheckout: "2" },
{ date: "2", totalCheckIn: "1", totalCheckout: "2" },
],
checkInLabel: ["Check In", "CheckOut"],
}
},
beforeMount() {
axios
.get('http://localhost:3000/monthly-checkin/'+this.month+'/'+this.year+'')
.then((res) => {
this.checkIn = res.data.monthly;
console.log(this.checkIn)
})
.catch((err) => {
console.log(err.response.data.message);
});
}
}
Please help
Use watch inside your BarChart component as below:
watch:{
chartData:function(newVal,OldVal){
//assign chart data
},
},
Afterwards you need to execute the method where your bar chart data could be updated. Below will be the full snippet.
import { Bar } from "vue-chartjs";
export default {
name: "BarChart",
extends: Bar,
data() {
return {};
},
props: {
label: {
type: Array,
},
chartData: {
type: Array,
},
options: {
type: Object,
},
},
watch: {
chartData: function (newVal, OldVal) {
this.updateChart()
},
},
mounted() {
this.updateChart()
},
methods: {
updateChart() {
const dates = this.chartData.map((d) => d.date);
const totalCheckIn = this.chartData.map((d) => d.totalCheckIn);
const totalCheckOut = this.chartData.map((d) => d.totalCheckout);
this.renderChart(
{
labels: dates,
datasets: [
{
label: this.label[0],
data: totalCheckIn,
},
{
label: this.label[1],
data: totalCheckOut,
},
],
},
this.options
);
}
}
};

Vue ChartJS not rendering when page reloads

This problem may seem to already exist but I also tried those and some are inactive now. My goal is to make the chart reactive whenever the page reloads. I tried to the solution from the Vue page itself i.e. add watchers and mixins but it doesn't work, as commented by others stuck like me. Mine only render if I change the width and height of the chart but everytime I refresh it, it disappears.
Dashboard.vue
<template>
<div align="center">
<LineChart :chartData="chartData" :options="options" style="width:auto;height:auto;" />
</div>
</template>
<script>
export default {
data() {
return {
chartData: {
labels: [],
datasets: [
{
data: [],
backgroundColor: "#3498db",
borderColor: "rgba(136,136,136,0.5)",
label: "",
},
],
},
options: {
responsive: true,
maintainAspectRatio: false,
title: {
display: true,
text: "Student's Score Chart",
},
tooltips: {
mode: "index",
intersect: false,
},
hover: {
mode: "nearest",
intersect: true,
},
scales: {
xAxes: [
{
display: true,
scaleLabel: {
display: true,
labelString: "Student Names",
},
},
],
yAxes: [
{
display: true,
scaleLabel: {
display: true,
labelString: "Score Points",
},
},
],
},
},
mounted() {
this.getListData();
},
methods: {
getListData() {
axios
.get("http://localhost/MyComposer/", {
params: {
answerId: 6,
token: this.token,
},
})
.then((response) => {
console.log(response.data);
for (var k = 0; k < response.data.length; k++) {
const fullName =
response.data[k].FirstName +
" " +
response.data[k].MiddleName +
" " +
response.data[k].LastName;
this.chartData.labels.push(
fullName + " (" + response.data[k].TestName + ") "
);
this.chartData.datasets[0].data.push(response.data[k].Score);
console.log(this.chartData);
}
})
.catch(function (error) {
console.log(error);
});
},
}
}
ChartContainer.js
import { Line, mixins } from 'vue-chartjs'
export default {
extends: Line,
mixins: [mixins.reactiveProp],
props: ['chartData', 'options'],
mounted () {
this.renderChart(this.chartData, this.options)
},
watch: {
chartData () {
this.renderChart(this.chartData, this.options)
}
}
}
I solved the problem. It was on the documentations all along. For you guys who didn't know, you should just add v-if to only enable the mounted method to activate when the page has loaded.
<line-chart
v-if="loaded"
:chart-data="this.chartData"
:options="this.options"
style="width:auto;height:auto;"
></line-chart>
data: {
loaded: false
}
getListData(){
this.loaded = true;
//My Axios API Request
}

vue-bootstrap4-table - how to modify filtering query params?

I use https://www.npmjs.com/package/vue-bootstrap4-table#8-filtering with django-rest-framework.
The problem is that this component uses totally different query params for sorting, filtering, etc.
vue-bootstrap4-table
http://127.0.0.1:8000/api/products/?queryParams=%7B%22sort%22:[],%22filters%22:[%7B%22type%22:%22simple%22,%22name%22:%22code%22,%22text%22:%22xxx%22%7D],%22global_search%22:%22%22,%22per_page%22:10,%22page%22:1%7D&page=1
"filters":[{"type":"simple","name":"code","text":"xxx"}],
but Django-rest-framework needs this format:
../?code__icontains=...
Do you know how to make vue-bootrstrap4-table to generate this format?
My app:
new Vue({
el: '#app',
data: {
product_list_url: "{% url "api:product-list" %}",
rows: [],
total_rows:0,
queryParams: {
sort: [],
filters: "",
global_search: "",
per_page: 10,
page: 1,
},
columns: [{
label: "Kód",
name: "code",
filter: {
type: "simple",
placeholder: "code"
},
sort: true,
},
{
label: "Názov",
name: "name",
filter: {
type: "simple",
placeholder: "Enter name"
},
sort: true,
},
],
config: {
checkbox_rows: true,
rows_selectable: true,
{#card_title: "Vue Bootsrap 4 advanced table",#}
server_mode: true,
}
},
mounted() {
this.fetchData();
},
methods: {
onChangeQuery(queryParams) {
this.queryParams = queryParams;
this.fetchData();
},
fetchData() {
let self = this;
axios.get(self.product_list_url, {
params: {
"queryParams": this.queryParams,
"page": this.queryParams.page
}
})
.then(function (response) {
self.rows = response.data.results;
self.total_rows = response.data.count;
})
.catch(function (error) {
console.log(error);
});
}
},
})

Categories

Resources