I try to display an array of object sort by date.
When it's mount there is no problem but when i try to add new data, it is not shown in the correct order. I'm sorry but I cannot be more clear ...
Here is my code :
<template>
<div class="container">
<div class="row">
<div class="col" style="position: relative; height: 50vh">
<canvas id="graphique"></canvas>
</div>
<div>
<h1>Finds</h1>
<div v-for="(find, index) in finds" v-bind:key="index">
<input v-model="find.date" />
<input v-model="find.value" />
<input v-model="find.label" />
</div>
<input v-model="dateToAdd" />
<input v-model="valueToAdd" />
<input v-model="labelToAdd" />
<button @click="addFind">Add cost</button>
<p v-if="Chart != null">{{ Chart.data.datasets[0].data }}</p>
</div>
</div>
</div>
</template>
<script>
import Chart from "chart.js/auto";
export default {
name: "PlanetChart",
data() {
return {
Chart: null,
valueToAdd: 20,
labelToAdd: "A",
dateToAdd: "12/01/1900",
finds: [
{ date: "12/01/2020", label: "1", value: 12 },
{ date: "12/01/2021", label: "2", value: 2 },
{ date: "12/01/2000", label: "0", value: 1 },
{ date: "12/01/2023", label: "3", value: 12 },
],
};
},
mounted() {
const ctx = document.getElementById("graphique");
this.finds.sort(function (a, b) {
return new Date(a.date) - new Date(b.date);
});
this.Chart = new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: "My dataset",
fill: false,
lineTension: 0.1,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
borderCapStyle: "butt",
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: "miter",
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 5,
pointHitRadius: 10,
data: this.finds,
},
],
},
options: {
parsing: {
xAxisKey: "date",
yAxisKey: "value",
},
responsive: true,
maintainAspectRatio: false,
},
});
},
methods: {
addFind: function () {
if (this.valueToAdd > 0 && this.labelToAdd != "") {
this.finds.push({
date: this.dateToAdd,
value: this.valueToAdd,
label: this.labelToAdd,
});
this.finds.sort(function (a, b) {
return new Date(a.date) - new Date(b.date);
});
this.Chart.data.datasets[0].data = this.finds;
console.log(this.Chart.data.datasets[0].data);
this.Chart.update();
this.valueToAdd = 0;
this.dateToAdd = "";
this.labelToAdd = "";
}
},
},
};
</script>
Here the result I have :
The point at the extrem right must be the first because his date is before the others points.
So it seems to be a rendering probleme and not a sort probleme.
If you need a js.fiddle let me know.
Thanks for your help !
EDIT : The only solution found is to create a function to create the graph and inside the addFind
function do this :
this.Chart.destroy();
this.Chart = this.createChart(this.finds)
CodePudding user response:
This is a working example with you data.
Here is the template code, I used a computed property to sort the array of data instead of sorting the actual data.
Please review the dependencies of the Chart.js package, as time series chart require external date adapters as mentioned here
Also, there seems to be a Chart.js wrapper for Vue, perhaps you should try it.
<template>
<div class="container">
<div class="row">
<div class="col" style="position: relative; height: 50vh">
<canvas id="graphique"></canvas>
</div>
<div>
<h1>Finds</h1>
<div v-for="(find, index) in finds" v-bind:key="index">
<input v-model="find.date" />
<input v-model="find.value" />
<input v-model="find.label" />
</div>
<input v-model="dateToAdd" />
<input v-model="valueToAdd" />
<input v-model="labelToAdd" />
<button @click="addFind">Add cost</button>
<p v-if="Chart">{{ Chart.data }}</p>
</div>
</div>
</div>
</template>
<script>
import Chart from "chart.js/auto";
import "chartjs-adapter-moment";
export default {
name: "PlanetChart",
data() {
return {
Chart: null,
valueToAdd: 20,
labelToAdd: "A",
dateToAdd: "12/01/1900",
finds: [
{ date: "12/01/2020", label: "1", value: 12 },
{ date: "12/01/2021", label: "2", value: 2 },
{ date: "12/01/2000", label: "0", value: 1 },
{ date: "12/01/2023", label: "3", value: 12 },
],
};
},
mounted() {
const ctx = document.getElementById("graphique");
this.Chart = new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: "US Dates",
backgroundColor: "#fff",
borderWidth: 1,
pointBorderWidth: 1,
borderColor: "#f00",
data: this.transformedData,
fill: false,
borderColor: "red",
},
],
},
options: {
scales: {
x: {
type: "time",
time: {
unit: "month",
},
},
},
},
});
},
computed: {
transformedData() {
const d = this.finds.map((i) => {
return { x: new Date(i.date), y: i.value };
});
d.sort(function (a, b) {
return a.x - b.x;
});
return d;
},
},
methods: {
addFind: function () {
if (this.valueToAdd > 0 && this.labelToAdd !== "") {
this.finds.push({
date: this.dateToAdd,
value: this.valueToAdd,
label: this.labelToAdd,
});
this.finds.sort(function (a, b) {
return new Date(a.date) - new Date(b.date);
});
this.Chart.data.datasets[0].data = this.transformedData;
console.log(this.Chart.data.datasets[0].data);
this.Chart.update();
this.valueToAdd = 0;
this.dateToAdd = "";
this.labelToAdd = "";
}
},
},
};
</script>
CodePudding user response:
So without using a computed method is it possible to do it simply by using the import "chartjs-adapter-moment";
as Juand David mentioned. And don't forget to convert the string in Date.
Here is my solution :
<template>
<div class="container">
<div class="row">
<div class="col">
<canvas id="graphique"></canvas>
</div>
</div>
<div class="row">
<div class="col-xxs">
<h1>Mes catégories</h1>
<div v-for="(cat, index) in category" v-bind:key="index">
{{ cat.label }}
</div>
</div>
<div class="col">
<h1>Mes dépenses</h1>
<div v-for="(find, index) in finds" v-bind:key="index">
<input v-model="find.date" readonly />
<input v-model="find.value" readonly />
<input v-model="find.label" readonly />
</div>
<div>
<input v-model="dateToAdd" />
<input v-model="valueToAdd" />
<select v-model="labelToAdd">
<option
v-for="(cat, index) in category"
:value="cat.label"
v-bind:key="index"
>
{{ cat.label }}
</option>
</select>
<button @click="addFind">Add cost</button>
</div>
</div>
</div>
</div>
</template>
<script>
import Chart from "chart.js/auto";
import "chartjs-adapter-moment";
export default {
name: "PlanetChart",
data() {
return {
ctx: null,
Chart: null,
valueToAdd: null,
labelToAdd: null,
dateToAdd: null,
category: [
{ id: "salary", label: "Salaire" },
{ id: "fun", label: "Loisir" },
],
finds: [
{ date: new Date("12/01/2020"), label: "Dépense 1", value: 12 },
{ date: new Date("12/01/2021"), label: "Salariée", value: 2 },
{ date: new Date("12/01/2000"), label: "Ciné", value: 1 },
{ date: new Date("12/01/2023"), label: "Restaurant", value: 12 },
],
};
},
mounted() {
this.ctx = document.getElementById("graphique");
this.finds.sort(function (a, b) {
return a.date - b.date;
});
this.Chart = this.createChart(this.finds);
},
methods: {
createChart: function (dataToAdd) {
var toRet = new Chart(this.ctx, {
type: "line",
data: {
datasets: [
{
label: "My dataset",
fill: false,
lineTension: 0.1,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
borderCapStyle: "butt",
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: "miter",
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 5,
pointHitRadius: 10,
data: dataToAdd,
},
],
},
options: {
parsing: {
xAxisKey: "date",
yAxisKey: "value",
},
scales: {
x: {
type: "time",
time: {
unit: "month",
},
},
},
responsive: true,
maintainAspectRatio: false,
},
});
return toRet;
},
addCategory: function () {},
addFind: function () {
if (this.valueToAdd !== null && this.labelToAdd !== null) {
this.finds.push( { date: new Date("12/01/1990"), label: "Dépense nouvelle", value: 5 });
this.finds.sort(function (a, b) {
return new Date(a.date) - new Date(b.date);
});
this.Chart.data.datasets[0].data = this.finds;
// console.log(this.Chart.data.datasets);
this.Chart.update();
// this.Chart = this.createChart(this.finds);
this.valueToAdd = 0;
this.dateToAdd = "";
this.labelToAdd = "";
}
},
},
};
</script>