Chartjs in Vue integrate parsed Json Data - javascript

i have amateur problems with building a Chart with Chart.js in Vue.js. Chart.js works, I can already see a Chart and am able log the data (with console.log) in the command line.
chart-data.js
type: 'line',
data: {
labels: ['Afghanistan', 'Somalia', 'Nigeria'],
datasets: [
{ // one line graph
label: 'Number of Moons',
data: [300, 75, 468],
backgroundColor: [
'rgba(54,73,93,.5)', // Blue
],
borderColor: [
'#36495d',
],
borderWidth: 3
},
{ // another line graph
label: 'Planet Mass (x1,000 km)',
data: [4.8, 12.1, 12.7, 6.7, 139.8, 116.4, 50.7, 49.2],
backgroundColor: [
'rgba(71, 183,132,.5)', // Green
],
borderColor: [
'#47b784',
],
borderWidth: 3
}
]
},
options: {
responsive: true,
lineTension: 1,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
padding: 25,
}
}]
}
}
}
export default planetChartData;
The parsing already works, but im struggling with getting my arrays (labelNation, numOfNationals) into the variable planetChartData.
json-parse.js
const file = fs.readFileSync('./data.json', 'utf8')
const test = JSON.parse(file)
let nationality = [];
for (let i = 0; i < test.length; i++) {
nationality.push(test[i].nationality)
}
const labelNation = Array.from(new Set(nationality));
let numOfNationals = [];
for (let i = 0; i < labelNation.length; i++) {
numOfNationals.push(nationality.filter(nat => nat === labelNation[i]).length)
}
vue.js
(in the script tag)
const Chart = require('chart.js');
import planetChartData from './chart-data.js';
export default {
name: 'App',
components: {
},
data() {
return {
planetChartData: planetChartData,
}
},
mounted() {
this.createChart('planet-chart', this.planetChartData);
},
methods: {
createChart(chartId, chartData) {
const ctx = document.getElementById(chartId);
const myChart = new Chart(ctx, {
type: chartData.type,
data: chartData.data,
options: chartData.options,
});
}
}
}
Thanks a lot for your help!

can you try this:
const Chart = require('chart.js');
import planetChartData from './chart-data.js';
export default {
name: 'App',
components: {
},
data() {
return {
planetChartData: planetChartData,
}
},
mounted() { // vvv use spread operator here below
this.createChart('planet-chart', ...this.planetChartData);
},
methods: {
createChart(chartId, chartData) {
const ctx = document.getElementById(chartId);
const myChart = new Chart(ctx, {
type: chartData.type,
data: chartData.data,
options: chartData.options,
});
}
}
}
and your chart-data.js should look like this for a decent export:
i am initializing a const for declaration of planetChartData
const planetChartData = {
type: "line",
data: {
labels: ["Afghanistan", "Somalia", "Nigeria"],
datasets: [
{
// one line graph
label: "Number of Moons",
data: [300, 75, 468],
backgroundColor: [
"rgba(54,73,93,.5)" // Blue
],
borderColor: ["#36495d"],
borderWidth: 3
},
{
// another line graph
label: "Planet Mass (x1,000 km)",
data: [4.8, 12.1, 12.7, 6.7, 139.8, 116.4, 50.7, 49.2],
backgroundColor: [
"rgba(71, 183,132,.5)" // Green
],
borderColor: ["#47b784"],
borderWidth: 3
}
]
},
options: {
responsive: true,
lineTension: 1,
scales: {
yAxes: [
{
ticks: {
beginAtZero: true,
padding: 25
}
}
]
}
}
};
export default planetChartData;

Related

react-chartjs-2 Radar Component

My Radar component hasnt ticks:{stepSize} property. Max is 5 and min is 1 but radar go up to 2. And I want it to jump one by one. more space between the triangles
i
nterface LineProps {
options: ChartOptions<"radar">;
data: ChartData<"radar">;
}
interface PropsComponent {
labels: string[];
data: number[];
}
interface PropsComponent {
labels: string[];
data: number[];
}
const Component = ({ labels, data }: PropsComponent) => {
const Props: LineProps = {
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: "top",
},
},
scales: {
ticks: {
beginAtZero: true,
max: 9,
min: 1,
},
},
},
data: {
datasets: [
{
label: "Datos",
data: data,
borderColor: "red",
backgroundColor: "red",
},
],
labels: labels,
},
};
labels = [criterion1,criterion2,criterion3]
values = [1,2,5]

react-chartjs-2 get visible values after pan/zoom with chartjs-plugin-zoom

Is there any way to get the visible values on a chart after zooming or panning, using react-chartjs-2? I found a solution without the react version, but I'm not sure how to reference the "chart object" in react. I tried the solution as is, but it doesn't display the visible values, but rather keeps increasing the height of my charts (stretches downwards).
So what would the react solution look like?
Here's my attempt with the linked solution
options:
const chartStyle = {
options: {
animation: false,
maintainAspectRatio: true,
responsive: true,
plugins: {
zoom: {
zoom: {
wheel: {
enabled: true,
modifierKey: "shift",
},
pinch: {
enabled: true,
},
enabled: true,
drag: true,
mode: "x",
onZoomComplete: getVisibleValues,
},
pan: {
enabled: true,
mode: "x",
speed: 2,
onPanComplete: getVisibleValues,
},
mode: "xy",
},
legend: {
display: false,
},
},
scales: {
y: {
type: "linear",
display: "true",
position: "left",
grid: {
drawBorder: true,
color: "#000000",
},
ticks: {
beginAtZero: true,
color: "#000000",
},
},
x: {
max: 9,
grid: {
drawBorder: true,
color: "#00000",
},
ticks: {
beginAtZero: false,
color: "#000000",
},
},
},
},
};
function getVisibleValues({ chart }) {
let x = chart.scales["x-axis-0"];
document.getElementById("vv").innerText = JSON.stringify(
chart.data.datasets[0].data.slice(x.minIndex, x.maxIndex + 1)
);
}
export default chartStyle;
Here's my attempt at accessing the chart instance with useRef(), but ref.scales is undefined:
const SingleChart = ({ chosenDevice, variable }) => {
const [chartData, setChartData] = useState({
labels: [],
datasets: [
{
label: variable,
data: [],
fill: false,
backgroundColor: "rgb(0,0,0)",
borderColor: "rgba(0,0,0, 0.8)",
color: "rgb(0,0,0)",
pointRadius: 4,
yAxisID: "y",
},
],
});
const [apiData, setApiData] = useState({});
const processEnv = process.env;
// USEREF ATTEMPT
const ref = useRef();
console.log(ref.scales);
let x = ref.scales["x"];
console.log("min index", x.minIndex);
console.log("max index", x.maxIndex);
useEffect(() => {
ChartComp.register(zoomPlugin);
var chartDataUrl = processEnv.REACT_APP_CHART_API + chosenDevice;
async function updatePPK() {
if (chosenDevice !== "") {
const dataResponse = await fetch(chartDataUrl);
var dataBody = await dataResponse.json();
for (var key in dataBody) {
dataBody[key].PV_POWER =
dataBody[key].PV_CURR * dataBody[key].PV_CURR;
}
setApiData(dataBody);
}
}
updatePPK();
}, [chosenDevice]);
useEffect(() => {
var chartLabels = [];
var chartValues = [];
console.log(apiData);
console.log("keys", Object.keys(apiData) !== 0);
if (Object.keys(apiData).length !== 0) {
for (var key in apiData) {
if (variable == "GEN_ON") {
chartValues.push(apiData[key][variable] == "ON" ? 1 : 0);
} else {
chartValues.push(apiData[key][variable]); // for every element in the passed in chartData object from hookMqtt, add the variable the graph requests (this.variable) to an array of data to be displayed
}
chartLabels.push(apiData[key]["TIME_COMMITED"].substring(11, 19));
}
setChartData({
labels: chartLabels,
datasets: [
{
label: variable,
data: chartValues,
fill: false,
backgroundColor: "rgb(0,0,0)",
borderColor: "rgba(0,0,0, 0.8)",
color: "rgb(0,0,0)",
pointRadius: 4,
yAxisID: "y",
},
],
});
console.log(chartData);
}
}, [chosenDevice, apiData]);
return (
<div>
<Line
ref={ref}
data={chartData}
options={variable != "GEN_ON" ? chartStyles.options : genStyle.options}
width={20}
height={10}
/>
</div>
);
};
SingleChart.propTypes = {
chartData: PropTypes.any,
chosenDevice: PropTypes.any,
setDate: PropTypes.any,
variable: PropTypes.any,
state: PropTypes.any,
};
export default SingleChart;

Adding condition in ComponentDidMount to display chart data

I've added a condition in componentDidMount to showcase data for either 1 or 2 datasets based on the pros recieved. However, I'm getting an error in the if condition. Here is BarChart component. Inside it, I've already imported Chart from 'chart.js'.
class BarChart1 extends Component {
constructor(props) {
super(props);
}
chartRef = React.createRef();
componentDidMount() {
const myChartRef = this.chartRef.current.getContext("2d");
let dataCheck = null;
if(this.props.data2){
let dataCheck = {
labels: this.props.labels,
datasets: [
{
label: this.props.label1,
backgroundColor: 'rgba(26,179,148,0.5)',
borderColor: "rgba(26,179,148,0.7)",
data: this.props.data1
}, {
label: this.props.label2,
backgroundColor: 'rgba(220, 220, 220, 0.5)',
pointBorderColor: "#fff",
data: this.props.data2
}
]
}
}
else {
let dataCheck = {
labels: this.props.labels,
datasets: [
{
label: this.props.label1,
backgroundColor: 'rgba(26,179,148,0.5)',
borderColor: "rgba(26,179,148,0.7)",
data: this.props.data1
}
]
}
}
new Chart(myChartRef, {
type: 'bar',
data: {dataCheck},
options: {
responsive: true,
maintainAspectRatio: false,
legend: {
display: true,
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
},
gridLines: {
display: false
}
}],
xAxes: [{
gridlines: {
display: false
},
ticks: {
fontSize: 9
}
}]
}
},
plugins: [{
beforeInit: function(chart) {
chart.data.labels.forEach(function(e, i, a) {
if (/\n/.test(e)) {
a[i] = e.split(/\n/);
}
});
}
}]
})
}
render() {
return <canvas ref={this.chartRef} />
}
}
I've edited my question. I'm now getting a blank chart without the error.
There are two errors in your code.
Your have to end the variable declaration with ; instead of ,
You have to declare datacheck outside the if else block unless you want it undefined
componentDidMount() {
...
let dataCheck;
if(this.props.data2){
dataCheck = {
...
}
}
else {
dataCheck = {
...
}
}
}

ChartJS makes unwanted horizontal line on Safari

I'm currently working with ChartJS.
It works fine on Firefox and Chrome.
On Safari there is horizontal lines which appear. (here there is one good on orange and two others unwanted )
I have a lot of datapoint (2 lines of 1600 data point). I don't know if it could be a cause.
My code is here.
In some other part, I update time uni and time min.
_displayChart: function(label1, label2){
var timeFormat = 'DD/MM/YYYY HH:mm';
var ctx = document.getElementById(this.heading).getContext('2d');
const data = {
// Labels should be Date objects
//labels:this._stats[1],
datasets: [{
fill: false,
label: label1,
data: this._stats[2],
borderColor: '#fe8b36',
pointRadius: 0,
backgroundColor: [
'#fe8b36'
]
},{
label: label2,
fill: false,
data: this._stats[3],
borderWidth: 1,
pointRadius: 0,
borderColor: 'rgba(99, 100, 200, 1)',
backgroundColor: [
'rgba(99, 100, 200, 0.2)'
]
}]
}
const options = {
type: 'line',
data: data,
options: {
responsive: false,
fill: false,
responsive: true,
maintainAspectRatio:!this._isMobile(),
max: this.max,
hover: {
// Overrides the global setting
mode: 'index'
},
annotation: {
drawTime: 'beforeDatasetsDraw',
events: ['click'],
annotations: []
},
legend: {
labels: {
filter: function(legendItem, chartData) {
if(legendItem.datasetIndex == 2 || legendItem.datasetIndex == 3 ){
return false;
}
return true;
}
}
},
tooltips: {
mode:'index',
intersect : false,
callbacks: {
title: function(tooltipItems, data) {
return tooltipItems[0].xLabel.format(timeFormat);
},
label: function(tooltipItems, data) {
return tooltipItems.yLabel+'%';
}
}
},
scales: {
xAxes: [{
type: 'time',
display: true,
time:{
unit:'day',
min:moment(Date.now()-this.monthTs),
max:this._stats[1][this._stats[1].length]
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
},
display: true
}]
}
}
}
this._chart = new Chart(ctx, options);
},
When I'm applying this, I have no problem:
this._chart.options.scales.xAxes[0].time.unit = 'month';
this._chart.options.scales.xAxes[0].time.stepSize = 1;
this._chart.options.scales.xAxes[0].time.min = this._stats[1][0];
this._chart.options.scales.xAxes[0].time.max = this._stats[1][this._stats[1].length-1];
Thanks

Chart.js stacked and grouped bar chart

is there any way to do a stacked and grouped bar chart with Chart.js library?
It should look something like this http://www.highcharts.com/demo/column-stacked-and-grouped
OK, I found the solution. It's described in this GitHub issue and solution is in this JSFiddle
Chart.defaults.groupableBar = Chart.helpers.clone(Chart.defaults.bar);
var helpers = Chart.helpers;
Chart.controllers.groupableBar = Chart.controllers.bar.extend({
calculateBarX: function (index, datasetIndex) {
// position the bars based on the stack index
var stackIndex = this.getMeta().stackIndex;
return Chart.controllers.bar.prototype.calculateBarX.apply(this, [index, stackIndex]);
},
hideOtherStacks: function (datasetIndex) {
var meta = this.getMeta();
var stackIndex = meta.stackIndex;
this.hiddens = [];
for (var i = 0; i < datasetIndex; i++) {
var dsMeta = this.chart.getDatasetMeta(i);
if (dsMeta.stackIndex !== stackIndex) {
this.hiddens.push(dsMeta.hidden);
dsMeta.hidden = true;
}
}
},
unhideOtherStacks: function (datasetIndex) {
var meta = this.getMeta();
var stackIndex = meta.stackIndex;
for (var i = 0; i < datasetIndex; i++) {
var dsMeta = this.chart.getDatasetMeta(i);
if (dsMeta.stackIndex !== stackIndex) {
dsMeta.hidden = this.hiddens.unshift();
}
}
},
calculateBarY: function (index, datasetIndex) {
this.hideOtherStacks(datasetIndex);
var barY = Chart.controllers.bar.prototype.calculateBarY.apply(this, [index, datasetIndex]);
this.unhideOtherStacks(datasetIndex);
return barY;
},
calculateBarBase: function (datasetIndex, index) {
this.hideOtherStacks(datasetIndex);
var barBase = Chart.controllers.bar.prototype.calculateBarBase.apply(this, [datasetIndex, index]);
this.unhideOtherStacks(datasetIndex);
return barBase;
},
getBarCount: function () {
var stacks = [];
// put the stack index in the dataset meta
Chart.helpers.each(this.chart.data.datasets, function (dataset, datasetIndex) {
var meta = this.chart.getDatasetMeta(datasetIndex);
if (meta.bar && this.chart.isDatasetVisible(datasetIndex)) {
var stackIndex = stacks.indexOf(dataset.stack);
if (stackIndex === -1) {
stackIndex = stacks.length;
stacks.push(dataset.stack);
}
meta.stackIndex = stackIndex;
}
}, this);
this.getMeta().stacks = stacks;
return stacks.length;
},
});
var data = {
labels: ["January", "February", "March"],
datasets: [
{
label: "Apples",
backgroundColor: "rgba(99,255,132,0.2)",
data: [20, 10, 30],
stack: 1
},
{
label: "Bananas",
backgroundColor: "rgba(99,132,255,0.2)",
data: [40, 50, 20],
stack: 1
},
{
label: "Cookies",
backgroundColor: "rgba(255,99,132,0.2)",
data: [60, 20, 20],
stack: 1
},
{
label: "Apples",
backgroundColor: "rgba(99,255,132,0.2)",
data: [20, 10, 30],
stack: 2
},
{
label: "Bananas",
backgroundColor: "rgba(99,132,255,0.2)",
data: [40, 50, 20],
stack: 2
},
{
label: "Cookies",
backgroundColor: "rgba(255,99,132,0.2)",
data: [60, 20, 20],
stack: 2
},
{
label: "Apples",
backgroundColor: "rgba(99,255,132,0.2)",
data: [20, 10, 30],
stack: 3
},
{
label: "Bananas",
backgroundColor: "rgba(99,132,255,0.2)",
data: [40, 50, 20],
stack: 3
},
{
label: "Cookies",
backgroundColor: "rgba(255,99,132,0.2)",
data: [60, 20, 20],
stack: 3
},
]
};
var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, {
type: 'groupableBar',
data: data,
options: {
legend: {
labels: {
generateLabels: function(chart) {
return Chart.defaults.global.legend.labels.generateLabels.apply(this, [chart]).filter(function(item, i){
return i <= 2;
});
}
}
},
scales: {
yAxes: [{
ticks: {
max: 160,
},
stacked: true,
}]
}
}
});
You should use the stack property of the dataset object for each dataset.
As you can see in Chart.js Documentation, stack is defined as:
"The ID of the group to which this dataset belongs to (when stacked, each group will be a separate stack)"
I believe this functionality has been introduced recently and in 2016 Chart.js did not have this because of this post
You can acheive stacked bar chart with below data
this.dataStackedBarChart = {
type: 'horizontalBar',
labels: this.stackedBarChartLabel,
datasets: [
{
label: 'Success Count',
stack: 'Stack 0',
data: this.successCount,
backgroundColor: 'green'
},
{
label: 'FailureCount',
stack: 'Stack 0',
data: this.failureCount,
backgroundColor: 'red'
},
{
label: 'AvgDuration',
stack: 'Stack 1',
data: this.avgDuration,
backgroundColor: 'black'
},
{
label: 'MaxDuration',
stack: 'Stack 2',
data: this.maxDuration,
backgroundColor: 'orange'
},
{
label: 'MinDuration',
stack: 'Stack 3',
data: this.minDuration,
backgroundColor: 'pink'
}
],
borderWidth: 2
}
this.optionsStackedBarChart = {
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
var label = this.uniqueApiPath[tooltipItem.index];
return label;
}
}
},
scales: {
xAxes: [
{
stacked: true,
display: true,
ticks: {
beginAtZero: true,
min: 0,
suggestedMin: 0
}
}
],
yAxes: [
{
stacked: true,
display: true,
ticks: {
beginAtZero: true,
min: 0,
suggestedMin: 0
}
}
]
}

Categories